精通Vue(17):transition实现原理(三)正常的动画进入

内容分享2个月前发布
3 0 0

这篇解决正常的动画进入,为什么称为正常进入呢,这是和首次渲染的比较。

首次渲染和正常渲染的区别

第15篇文章中提到,组次首次进入就缓动是一个特例,但首次进入这个字面意思就比较费解,下面解释一下:

首次进入

列如下面的代码:

<transition>
  <div></div>
</transition>

第一创建transition,由于它包裹的“儿子”DOM是现成的,所以直接顺带把它挂上去了,也即创建transition的同时将DOM也挂上去了,这称为首次进入。

第二种情况

<transition>
  <div v-if="show"></div>
</transition>

开始建transition,由于开始show为false,所以父亲没有儿子,它自己建好了。过一会我们点击按钮,v-if为真,那么div就挂上来了,但此时它父亲早已建好,这种状态就称为正常的显隐。

也就是说,transition是先创建好的,“儿子”是后面某个时机挂载上去的。通过这么对比,我们就清楚了,为什么首次进入只会执行一次,由于transition本身的创建只有一次,虽然它内部的DOM可以换来换去,但它本身只创建了一次。

目前我们可以做个总结,首次动画和正常动画是以transition这个组件的创建与否做为参照标准的。

第15篇就是讲第一种情况,而本篇是写第二种情况。

缓动四大件

虽然动画DOM是后面加进去的,但它同样遵循缓动四件套,即开始状态、结束状态、缓动规则和动作触发。

这里Vue有两套查找规则,第一种是默认的class,第二种是命名的class。

默认的css和命名的css

如果不明确指定,Vue就会在css定义中找下面三个class:

v-enter
v-enter-active
v-enter-to

如果transition具有name属性,那么就会使用name开头的class样式,相当于给用户一个命名的机会,动画的三个class命名规则如下:

${name}-enter
${name}-enter-active
${name}-enter-to

列如:

<transition name="box">
    <div class="box" v-if="show"></div>
</transition>

在这个代码中,transition有一个name属性,那么Vue就会在CSS中查找下面的样式:

box-enter
box-enter-active
box-enter-to

缓动的触发动作

和第15文章一样,触发动作也是在下一帧回调中执行的。

实验:显示DOM时,让它从右侧滑入

第一看效果图:

精通Vue(17):transition实现原理(三)正常的动画进入

需求:在DOM显示时,让它先从偏离X 100px开始,然后经过缓动到达div正常位置。

代码如下:

精通Vue(17):transition实现原理(三)正常的动画进入

分析:这个代码发生一个重大问题,就是.box-enter-to即结束状态不见了!!但好在,我们在说缓动四件套的时候也提到过,状态是可选的,也就是说开始状态和结束状态的两者任一是可选的。

目前的情况是有开始,没有结束。那么状态差值是怎么产生的呢?

这个问题在第15篇文章中没有提到,那么这个问题是怎么解决呢?

问题是这样的:

//第一次渲染
增加.box-enter
增加.box-enter-active

//第二次渲染前的回调
删除.box-enter
增加.box-enter-to

可以看到在回调中删除.box-enter开始状态,除了是清理,还有一个重大的功能就是应付我们这个问题的,也就是说如果没有结束状态,它把开始状态删除了,就是一下又回到原始状态了,那么原始状态和开始状态之间比较就有差值了,就好比你先把弹簧拉长(开始),然后再让它回到原始位置(结束),超级精彩!!

同样,我们还可以做成没有开始,只有结束,原理是一样。

最后,transition有了一个具体的name,那么Vue就会查找以${name}-打头的CSS。

离开动画

组件创建之后,也可能会销毁。目前我们再看下离开时的动画,代码如下:

精通Vue(17):transition实现原理(三)正常的动画进入

分析:和正常显示动画一样,不过以${name}-leave开头,原理几乎一样,这里不再赘述。

总结

这篇主要说明了下面几个重大问题:

  1. 首次缓动和正常缓动的区别。
  2. 正常缓动的命名CSS
  3. 离开缓动的使用

完整的实验代码

代码完整演示了正常进入缓动和退出缓动

<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .box {
            width: 200px;
            height: 100px;
            background: #673ab7;
            color: white;
            text-align: center;
            line-height: 100px;
            margin: 20px;
        }
        .box-enter {transform: translateX(100px);}
        .box-enter-active {transition: all 1s ease;}

        .box-leave-active{transition: all 1s ease;}
        .box-leave-to{transform: translateX(-100px);}
    </style>
</head>
<body>
<div id="app">
    <button @click="show=!show">
        {{show?'隐藏动画组件':'显示动画组件'}}
    </button>
    <transition name="box">
        <div class="box" v-if="show"></div>
    </transition>
</div>
<script src="../vue.js"></script>
<script>
    new Vue({
        el: '#app',
        data() {
            return {
                show: false
            }
        }
    })
</script>
</body>
© 版权声明

相关文章

暂无评论

none
暂无评论...