精通Vue(16):transition实现原理(二)回调

什么是回调?

回调就是指动画执行前、后留给用户的一个处理机会,看它的运行时机比较好理解一些:

精通Vue(16):transition实现原理(二)回调

从图示中可以看到有三个回调。

第一个回调:before-enter

它发生在动画dom安装class之前。那么vue就会喊一下,我要准备安装缓动class了,要不要处理一下?可以看到实参是el元素,在这里我们可以设置el的一些初始状态,可以想像是生产之前的准备工作。

第二个回调:enter

发生在一切准备就绪,且下一帧渲染之前的地方。 Vue会喊一下,我们马上就要开始执行动画了,要不要处理一下?

这个地方比较重大,由于它会同时将cb传进来,是什么意思呢?

cb是Vue内部做的一个动画结束处理回调,简单说就是,如果用户什么都没说,Vue会在内部生成一个默认的回调,这个回调就处理动画结束之后的善后工作,列如清理class等,在许多情况下我们是偷懒的,所以直接默认用它的。

但有时我们需要自己掌控一些细节,也就是说有些特殊场景Vue不能帮我们做。

好吧,这里就给用户留一个接口,你要不要处理一下?如果我们用了两个形参,那么Vue就认为我们想自定义动画结束的处理,但是它为什么要把cb也一块传过来呢?

由于这个cb是托底的。打个比方说,我们先自己处理,处理完成之后再调用Vue的cb,让它帮我们做一些善后工作,我们就轻松许多。假定没有这个cb,又要重新写一次,模型如下:

enter(el,cb){
    //自定义结束回调
    el.addEventListener('transitionend',function (){
        //做我们自己的业务...
        el.style.border='1px solid blue'
        el.innerText='动画结束了!'
        //执行Vue的默认回调,(可选)...
        cb()
    })
},

分析:在这个代码中,我们完全掌控了动画结束之后的处理,通俗说就是这个事不用Vue来了我自己做。因此在这里自定义了一个transitionend的回调,在内部做我们的任务。在最后我们再调用Vue的默认回调,这样省了许多事。

可以看出,这是精细控制动画结束的一个重大时机!

另外需要提的是,浏览器渲染是异步的,列如说我们把class加到一个div上是不会马上生效的,由于下一帧的渲染之前必须清空当前线程栈,也就是当前主线程必须全部执行完成。而我们看到enter还在主线程中执行中,所以就轮不到下一次渲染,这就是enter的运行时机。

第三个回调:after-enter

缓动结束之后,也就是transitionend的善后处理工作完成之后,就执行after-enter回调。这说明动画已经彻底完成了。

正常流程下,它是在Vue内部的cb中执行的。如果我们自定义了回调且没有调用Vue的cb,那么这个after-enter不会执行。

完整的实验代码

    <style>
        .box {
            width: 200px;
            height: 200px;
            text-align: center;
            line-height: 100px;
            margin: 20px;
        }

        .my-appear-class {
            transform: translateX(100px);
        }

        .my-active-class {
            transition: all 1s ease;
        }

        .my-to-class {
            transform: translateX(50px);
        }
    </style>
</head>
<body>
<div id="app">
    <button @click="show=!show">{{show ? '隐藏动画' : '显示动画'}}</button>
    <transition
            appear-class="my-appear-class"
            appear-active-class="my-active-class"
            appear-to-class="my-to-class"
            appear
            @before-enter="beforeEnter"
            @enter="enter"
            @after-enter="afterEnter"
    >
        <div class="box">
            首次加载会从右边滑入
        </div>
    </transition>
</div>
<script src="../vue.js"></script>
<script>
    new Vue({
        el: '#app',
        data() {
            return {
                show: false
            }
        },
        methods: {
            beforeEnter(el) {
                //设置状态,列如一个样式...
                el.style.border="1px solid red"
            },
            enter(el,cb){
                //自定义结束回调
                el.addEventListener('transitionend',function (){
                    //做我们自己的业务...
                    el.style.border='1px solid blue'
                    el.innerText='任务完成!'
                    //执行Vue的默认回调,(可选)...
                    cb()
                })
            },
            afterEnter(el) {
                alert('动画完全结束了!!!')
            }
        }
    })
</script>
© 版权声明

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
none
暂无评论...