Vue学习—深入剖析单元素过渡

一、单元素过渡

Vue 在插入、更新或者移除 DOM 时,提供多种不同方式的应用过渡效果。

1.单元素/组件的过渡

Vue 提供了 transition 的封装组件,在下列情形中,可以给任何元素和组件添加进入/离开过渡

  • 条件渲染 (使用 v-if)
  • 条件展示 (使用 v-show)
  • 动态组件
  • 组件根节点

2.过渡的类名

在进入/离开的过渡中,会有 6 个 class 切换。
1. v-enter
定义进入过渡的开始状态。
在元素被插入之前生效,在元素被插入之后的下一帧移除。

2. v-enter-active
定义进入过渡生效时的状态。
在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。
这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。

3. v-enter-to:
定义进入过渡的结束状态(2.1.8+) 。
在元素被插入之后下一帧生效 (与此同时 v-enter 被移除),在过渡/动画完成之后移除。

4. v-leave
定义离开过渡的开始状态。
在离开过渡被触发时立刻生效,下一帧被移除。

5. v-leave-active
定义离开过渡生效时的状态。
在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。
这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。

5. v-leave-to:
定义离开过渡的结束状态(2.1.8+) 。
在离开过渡被触发之后下一帧生效 (与此同时 v-leave 被删除),在过渡/动画完成之后移除。

在这里插入图片描述

<template>
  <div class="demo">
    <button @click="show = !show">click</button>
    <transition>
      <div  class="box" v-show="show">hellow world</div>
    </transition>
  </div>
</template>

<script>
export default {
     
     
  data(){
     
     
    return {
     
     
      show: true
    }
  }
}
</script>

<style scoped>
button {
     
     
  margin-bottom: 10px;
}

.box {
     
     
  width: 100px;
  height: 100px;
  line-height: 100px;
  text-align: center;
  border: 1px solid red;
  color: red;
}

.v-enter {
     
     
  opacity: 0;
  transform: translateX(250px);
}

.v-enter-active {
     
     
  transition: all 0.8s;
}

.v-enter-to {
     
     
  opacity: 1;
  transform: translateX(0px);
}

.v-leave {
     
     
  opacity: 1;
  transform: translateX(0px);
}

.v-leave-active {
     
     
  transition: all 0.8s;
}

.v-leave-to {
     
     
  opacity: 0;
  transform: translateX(250px);
}
</style>

在这里插入图片描述
在这里插入图片描述

3.类名前缀

  1. transition 无 name 特性
    类名前缀为 v-。
.v-enter {
    
    
  opacity: 0;
  transform: translateX(250px);
}

.v-enter-active {
    
    
  transition: all 0.8s;
}

.v-enter-to {
    
    
  opacity: 1;
  transform: translateX(0px);
}

.v-leave {
    
    
  opacity: 1;
  transform: translateX(0px);
}

.v-leave-active {
    
    
  transition: all 0.8s;
}

.v-leave-to {
    
    
  opacity: 0;
  transform: translateX(250px);
}
  1. transition 有 name 特性
    如 name 为 fade,则类名前缀为fade-。
<template>
  <div class="demo">
    <button @click="show = !show">click</button>
    <transition name="box1">
      <div class="box" v-if="show">hello world</div>
    </transition>
    <transition name="box2">
      <div class="box" v-if="show">hello world</div>
    </transition>
  </div>
</template>

<script>
export default {
    
    
  data () {
    
    
    return {
    
    
      show: true,
    }
  }
}
</script>

<style scoped>
button {
    
    
  margin-bottom: 10px;
}

.box {
    
    
  width: 100px;
  height: 100px;
  margin-bottom: 10px;
  line-height: 100px;
  text-align: center;
  border: 1px solid red;
  color: red;
}
/* 合并代码,减少耦合和代码量 */
.box1-enter,
.box1-leave-to {
    
    
  opacity: 0;
  transform: translateX(200px);
}

.box1-enter-active,
.box1-leave-active {
    
    
  transition: all .3s;
}

.box1-enter-to,
.box1-leave {
    
    
  opacity: 1;
  transform: translateX(0px);
}

.box2-enter-to,
.box2-leave {
    
    
  opacity: 1;
  transform: translateY(0px);
}

.box2-enter-active,
.box2-leave-active {
    
    
  transition: all .3s;
}

.box2-enter,
.box2-leave-to {
    
    
  opacity: 0;
  transform: translateY(200px);
}
</style>

在这里插入图片描述
在这里插入图片描述

4.CSS 动画

CSS 动画用法同 CSS 过渡,区别是在动画中 v-enter 类名在节点插入 DOM 后不会立即删除,而是在 animationend 事件触发时删除。

<template>
  <div class="demo">
    <button @click="show = !show">click</button>
    <transition>
      <div class="box" v-if="show">hello world</div>
    </transition>
  </div>
</template>

<script>
export default {
    
    
  data () {
    
    
    return {
    
    
      show: true,
    }
  }
}
</script>

<style scoped>
button {
    
    
  margin-bottom: 10px;
}

.box {
    
    
  width: 100px;
  height: 100px;
  margin-bottom: 10px;
  line-height: 100px;
  text-align: center;
  border: 1px solid red;
  color: red;
}

.v-enter-active {
    
    
  animation: animate 1s;
}

.v-leave-active {
    
    
  animation: animate 1s reverse;
}

@keyframes animate {
    
    
  0% {
    
    
    opacity: 0;
    transform: translateX(400px) scale(1);
  }

  50% {
    
    
    opacity: .5;
    transform: translateX(200px) scale(1.5);
  }

  100% {
    
    
    opacity: 1;
    transform: translateX(0) scale(1);
  }
}
</style>

在这里插入图片描述
在这里插入图片描述

5.自定义过渡的类名

我们可以通过以下 attribute 来自定义过渡类名:

  • enter-class
  • enter-active-class
  • enter-to-class (2.1.8+)
  • leave-class
  • leave-active-class
  • leave-to-class (2.1.8+)
<template>
  <div class="demo">
    <button @click="show = !show">click</button>
    <transition enter-active-class="enter" leave-active-class="leave">
      <div class="box" v-if="show">hello world</div>
    </transition>
  </div>
</template>

<script>
export default {
    
    
  data () {
    
    
    return {
    
    
      show: true,
    }
  }
}
</script>

<style scoped>
button {
    
    
  margin-bottom: 10px;
}

.box {
    
    
  width: 100px;
  height: 100px;
  margin-bottom: 10px;
  line-height: 100px;
  text-align: center;
  border: 1px solid red;
  color: red;
}

.enter {
    
    
  animation: animate 1s;
}

.leave {
    
    
  animation: animate 1s reverse;
}

@keyframes animate {
    
    
  0% {
    
    
    opacity: 0;
    transform: translateX(400px) scale(1);
  }

  50% {
    
    
    opacity: .5;
    transform: translateX(200px) scale(1.5);
  }

  100% {
    
    
    opacity: 1;
    transform: translateX(0) scale(1);
  }
}
</style>

他们的优先级高于普通的类名,这对于 Vue 的过渡系统和其他第三方 CSS 动画库(如 Animate.css)结合使用十分有用。
由于我们不会愿意花太多时间去写一个好的动画,那么通过命名就能对各样动画进行命名。

下面推荐一款动画的css
Animate.css 官网地址:https://daneden.github.io/animate.css/
安装方式:npm install animate.css --save,最后引入css
在这里插入图片描述

<template>
  <div class="demo">
    <button @click="show = !show">click</button>
    <transition 
    enter-active-class="animated bounceInRight"
    leave-active-class="animated bounceOutDown">
      <div class="box" v-if="show">hello world</div>
    </transition>
  </div>
</template>

6.同时使用过渡和动画

可使用 type 属性,来声明需要 Vue 监听的类型,type值可为 animation 或 transition 。

当不设置type时,默认会取 transitioned 和 animationed 两者更长的为结束时刻。(以哪个为主)

<template>
  <div class="demo">
    <button @click="show = !show">click</button>
    <transition
      type="animation"
      enter-active-class="animated tada v-enter-active"
      leave-active-class="animated tada v-leave-active"
    >
      <div class="box" v-if="show">hello world</div>
    </transition>
  </div>
</template>

<script>
export default {
    
    
  data () {
    
    
    return {
    
    
      show: true,
    }
  }
}
</script>

<style scoped>
button {
    
    
  margin-bottom: 10px;
}

.box {
    
    
  width: 100px;
  height: 100px;
  margin-bottom: 10px;
  line-height: 100px;
  text-align: center;
  border: 1px solid red;
  color: red;
}

.v-enter,
.v-leave-to {
    
    
  opacity: 0;
}

.v-enter-active,
.v-leave-active {
    
    
  transition: all 5s;
}

.v-enter-to,
.v-leave {
    
    
  opacity: 1;
}

</style>

7.显性的过渡时间

在一些情况下,Vue可以自动得出过渡效果的完成时机,从而对dom进行处理。

但是有些时候,我们会设置一系列的过渡效果,例如嵌套元素也有过渡动效,其过渡效果的时间长于父元素。此时我们可以设置duration属性,定制一个显性的过渡持续时间(以毫秒记):

<transition :duration="1000">...</transition>
<transition :duration="{ enter:400,leave:600 }">...</transition>

也可以定制进入和移出的持续时间:

<transition :duration="{ enter: 500, leave: 800 }">...</transition>

8.初始渲染的过渡

可以通过 appear attribute 设置节点在初始渲染的过渡。

和进入/离开过渡一样,同样也可以自定义 CSS 类名。如:

appear-class="appear-enter"
appear-active-class="appear-enter-active"
appear-to-class="appear-enter-to"

<template>
  <div class="demo">
    <button @click="show = !show">click</button>
    <transition
      :duration="1000"
      appear    //进入就显示
      appear-active-class="animated swing"
      enter-active-class="animated tada"
      leave-active-class="animated tada"
    >
      <div class="box" v-if="show">hello world</div>
    </transition>
  </div>
</template>

9.JavaScript 钩子

可以在属性中声明 JavaScript 钩子:

<transition
  @before-enter="beforeEnter"  //入场前
  @enter="enter"  //中
  @after-enter="afterEnter"  //后
  @enter-cancelled="enterCancelled"    //取消,用的很少

  @before-leave="beforeLeave"
  @leave="leave"
  @after-leave="afterLeave"
  @leave-cancelled="leaveCancelled"
>
  <!-- ... -->
</transition>
<template>
  <div class="demo">
    <button @click="show = !show">click</button>
    <transition
      :css="false"
      @before-enter="beforeEnter"
      @enter="enter"
      @after-enter="afterEnter"
      @enter-cancelled="enterCancelled"
    >
      <div class="box" v-if="show">hello world</div>
    </transition>
  </div>
</template>

<script>
export default {
    
    
  data () {
    
    
    return {
    
    
      show: true,
      x: 200,
    }
  },
  methods: {
    
    
    beforeEnter (el) {
    
    
      el.style.transform = 'translateX(200px)';
    },
    enter (el, done) {
    
    
      //done.canceled = true;//一旦动画取消,就会执行enterCancelled函数
      const timer = setInterval(() => {
    
    
        this.x -= 2;
        el.style.transform = `translateX(${
      
      this.x}px)`;

        if(this.x <= 0) {
    
    
          clearInterval(timer);
          done();//done不执行,after就不会执行
        }
      }, 10)
    },
    afterEnter () {
    
    
      this.x = 200;
    },
    enterCancelled: function () {
    
    
      // console.log('cancel');
      // this.isCancel = true;
    }
  }
}
</script>

<style scoped>
button {
    
    
  margin-bottom: 10px;
}

.box {
    
    
  width: 100px;
  height: 100px;
  margin-bottom: 10px;
  line-height: 100px;
  text-align: center;
  border: 1px solid red;
  color: red;
}


</style>
  • before-enter 动画入场前,可以在其中设置元素开始动画之前的起始样式
  • enter 动画入场中,可以在其中写动画
  • after-enter 动画完成后
  • enter-cancelled 取消动画

对于仅使用 JavaScript 过渡的元素添加 v-bind:css=“false”,Vue 会跳过 CSS 的检测。这也可以避免过渡过程中 CSS 的影响。

设置了 appear 特性的 transition 组件,也存在自定义 JavaScript 钩子:

<transition
  appear
  v-on:before-appear="customBeforeAppearHook"
  v-on:appear="customAppearHook"
  v-on:after-appear="customAfterAppearHook"
  v-on:appear-cancelled="customAppearCancelledHook"
>
  <!-- ... -->
</transition>

结合 Velocity.js
继续懒,所以有了js的动画插件
Velocity.js 官网地址:http://velocityjs.org/
安装方式: npm install velocity-animate

<template>
  <div class="demo">
    <button @click="show = !show">click</button>
    <transition
      :css="false"
      @before-enter="beforeEnter"
      @enter="enter"
      @before-leave="beforeLeave"
      @leave="leave"
    >
      <div class="box" v-if="show">hello world</div>
    </transition>
  </div>
</template>

<script>
export default {
    
    
  data () {
    
    
    return {
    
    
      show: true,
    }
  },
  methods: {
    
    
    beforeEnter (el) {
    
    
      el.style.opacity = 0;
    },
    enter (el, done) {
    
    
      Velocity(el, {
    
     opacity: 1}, {
    
     duration: 500});
      Velocity(el, {
    
     rotateZ: 10 }, {
    
     duration: 300 });
      Velocity(el, {
    
     rotateZ: -10 }, {
    
     duration: 300 });
      Velocity(el, {
    
     rotateZ: 0 }, {
    
     duration: 300, complete: done });
    },
    beforeLeave (el) {
    
    
      el.style.transformOrigin = 'left';
    },
    leave (el, done) {
    
    
      Velocity(el, {
    
     translateX: '15px', rotateZ: '50deg'}, {
    
     duration: 600});
      Velocity(el, {
    
     rotateZ: '100deg'}, {
    
     duration: 600, loop: 2});
      Velocity(el, {
    
     rotateZ: '45deg', translateY: '30px', translateX: '30px', opacity: 0}, {
    
     complete: done});
    },
  }
}
</script>

<style scoped>
button {
    
    
  margin-bottom: 10px;
}

.box {
    
    
  width: 200px;
  margin-bottom: 10px;
  text-align: center;
  border: 1px solid red;
  color: red;
}


</style>

猜你喜欢

转载自blog.csdn.net/xun__xing/article/details/108553877