Vue 过渡动画

本文详细介绍了Vue中<transition>和<transition-group>的使用,包括进入/离开/移动过渡,列表过渡,以及状态过渡。重点讲解了CSS动画、自定义过渡类名、JavaScript钩子函数和多个元素过渡的实现,同时也提到了Vue过渡动画的进阶用法和注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

进入(v-enter)/离开(v-leave)/移动(v-move)&列表(transition-group)的过渡

简单的例子:

<div id="demo">
  <button @click="show = !show"> Toggle </button>
  <transition name="fade">
    <p v-if="show">hello</p>
  </transition>
</div>
new Vue({
  el: '#demo',
  data: { show: true }
})
.fade-enter-active, .fade-leave-active {
  transition: opacity .5s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
  opacity: 0;
}

1. 使用 <transition> 标签包裹需要过渡动画的元素,vue会在适当时候给元素添加类名。

2. 被 <transition> 标签包裹的元素需要使用条件渲染("v-if"/"v-show")。

3. 在 <transition> 标签内的 "name" 属性为动画提供具名,也可能缺省,则以 "v-" 作为前缀。

4. 以上配置并不会在首次渲染生效,使用 "appear" 属性解决,具体查看下面的 "初始渲染的过渡" 。

注意,若 "v-if"/"v-show" 放在组件内部只会产生"进入过度"。解决办法是把 "v-if"/"v-show" 放在父组件中。错误示范如下:

<div id="container">
  <button @click="isShow=!isShow">显示/隐藏</button>
  <transition>
    <child/>
    <!-- <child v-if="isShow"> -->  <!-- 正确做法 -->
  </transition>
</div>
<script>
Vue.component('child',{
  template: '<div v-if="$root.isShow" style="background:green;width:100px;height:100px;">子组件</div>'
});
new Vue({
  el: '#container',
  data() { return { isShow: false } }
});
</script>
<style>
  .v-enter-active, .v-leave-active { transition: opacity .5s; }
  .v-enter, .v-leave-to { opacity: 0; }
</style>

 


初始渲染的过渡:

<!-- 添加 appear 属性后可在首次渲染有 enter 过渡动画 -->
<transition appear><!-- ... --></transition>
<!-- 同样可以指定自定义类名及JS钩子函数,具体做法查看官方文档 -->

过渡的类名( 6个 ):

1. v-enter:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。

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

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

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

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

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


CSS动画:[ animation ]

.bounce-enter-active {
  animation: bounce-in .5s;
}
.bounce-leave-active {
  animation: bounce-in .5s reverse;
}
@keyframes bounce-in {
  0% { transform: scale(0); }
  50% { transform: scale(1.5); }
  100% { transform: scale(1); }
}

自定义过渡的类名:[ 结合第三方css库: animate.css ]

<!-- 引入 animate.css 库 -->
<link href="https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel="stylesheet" type="text/css">
<div id="example-3">
  <button @click="show = !show">
    Toggle render
  </button>
  <!-- 以属性方式指定特定类名 -->
  <transition
    name="custom-classes-transition"
    enter-active-class="animated tada"
    leave-active-class="animated bounceOutRight"
  >
    <p v-if="show">hello</p>
  </transition>
</div>

animate.css库使用方法:

在官网(https://daneden.github.io/animate.css/)上找到合适的动画,如上方法添加指定的类名(必须带有"animated"类名)。


持续时长:

同时使用过渡(transition)和动画(animation),可能存在时长不同,使用 type 特性并设置 animation 或 transition 来明确以哪个为时长标准。

<!-- 以 transition 时长为标准 -->
<transition type="transition">...</transition>

为 <transition> 标签添加具体持续时长

<!-- 定制一个显性的过渡持续时间 (以毫秒计):-->
<transition :duration="1000">...</transition>
<!-- 你也可以定制进入和移出的持续时间:-->
<transition :duration="{ enter: 500, leave: 800 }">...</transition>

JS钩子函数: [ 结合第三方JS动画库: Velocity.js ]

<!-- Velocity 和 jQuery.animate 的工作方式类似,也是用来实现 JavaScript 动画的一个很棒的选择 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>
<div id="example-4">
  <button @click="show = !show"> Toggle </button>
  <transition
    v-on:before-enter="beforeEnter"
    v-on:enter="enter"
    v-on:leave="leave"
    v-bind:css="false"
  >
    <p v-if="show"> Demo </p>
  </transition>
</div>
new Vue({
  el: '#example-4',
  data: {
    show: false
  },
  methods: {
    beforeEnter: function (el) {
      el.style.opacity = 0
      el.style.transformOrigin = 'left'
    },
    enter: function (el, done) {
      Velocity(el, { opacity: 1, fontSize: '1.4em' }, { duration: 300 })
      Velocity(el, { fontSize: '1em' }, { complete: done })
    },
    leave: function (el, done) {
      Velocity(el, { translateX: '15px', rotateZ: '50deg' }, { duration: 600 })
      Velocity(el, { rotateZ: '100deg' }, { loop: 2 })
      Velocity(el, {
        rotateZ: '45deg',
        translateY: '30px',
        translateX: '30px',
        opacity: 0
      }, { complete: done })
    }
  }
})

1. 当只用 JavaScript 过渡的时候,在 enter 和 leave 中必须使用 done 进行回调。否则,它们将被同步调用,过渡会立即完成。

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

3. Velocity.js 的具体用法请查看文档(http://www.mrfront.com/docs/velocity.js/index.html)。


多个元素的过渡: [ transition标签内包含v-if/v-else ]

1. 默认情况下 <transition> 内的组件是进入/离开同时发生,要改变需要设置 "mode" 属性。

<!-- 先出后入,先入后出则输入"in-out" -->
<transition name="fade" mode="out-in">
  <!-- ... the buttons ... -->
</transition>

2. 当有相同标签名的元素切换时,需要通过 key 特性设置唯一的值来标记以让 Vue 区分它们,否则 Vue 为了效率只会替换相同标签内部的内容。

<transition>
  <button v-if="isEditing" key="save"> Save </button>
  <button v-else key="edit"> Edit </button>
</transition>

列表过渡: [ transition-group标签内包含v-for ]

与transition类似。使用场景是,用v-for渲染列表,当数据源发生变化,对应的列表项需要过渡动画。有几点需要注意,过渡元素不可用(如v-mode="out-in");内部元素均需要唯一的"key"属性; <transition-group> 渲染呈现为真实标签,默认是"span",可以通过"tag"属性指定特有标签

<div id="list-demo" class="demo">
  <!-- 修改数据源的按钮 -->
  <button v-on:click="add">Add</button>
  <button v-on:click="remove">Remove</button>
  <!-- transition-group 渲染为 p 标签 -->
  <transition-group name="list" tag="p">
    <span v-for="item in items" v-bind:key="item" class="list-item">
      {{ item }}
    </span>
  </transition-group>
</div>

列表的排序过渡: [ v-move ]

与 enter/leave 用法类似,用 "v-move" 实现列表元素的移动,可以通过 name 属性来自定义前缀,也可以通过 move-class 属性手动设置。

<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.14.1/lodash.min.js"></script> 操作数组的JS库 -->
<div id="flip-list-demo" class="demo">
  <button v-on:click="shuffle">Shuffle</button>
  <transition-group name="flip-list" tag="ul">
    <!-- 改变数组顺序:shuffle(){this.items = _.shuffle(this.items)} -->
    <li v-for="item in items" v-bind:key="item">
      {{ item }}
    </li>
  </transition-group>
</div>
.flip-list-move {
  transition: transform 1s;
}

进阶用法:https://jsfiddle.net/chrisvfritz/sLrhk1bc/

 



状态过渡

数值变化的过渡动画: [ TweenMax.js ]

<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.3/TweenMax.min.js"></script>
<div id="animated-number-demo">
  <input v-model.number="number" type="number" step="20">
  <p>{{ animatedNumber }}</p>
</div>
new Vue({
  el: '#animated-number-demo',
  data: {
    number: 0,
    tweenedNumber: 0
  },
  computed: {
    animatedNumber: function() {
      return this.tweenedNumber.toFixed(0);
    }
  },
  watch: {
    // 监听数值变化,动态演示数值的增减,依赖TweenMax.min.js库
    number: function(newValue) {
      TweenLite.to(this.$data, 0.5, { tweenedNumber: newValue });
    }
  }
})

颜色变化的过渡动画:

方法与上述数值变化过渡动画类似,同样是获取值,使用指定库函数赋值,以达到动态显示变化的效果。

依赖 Tween.jsColor.js 。具体查看官方文档例子:https://cn.vuejs.org/v2/guide/transitioning-state.html#%E7%8A%B6%E6%80%81%E5%8A%A8%E7%94%BB%E4%B8%8E%E4%BE%A6%E5%90%AC%E5%99%A8


其他数值变化的过渡动画,实现的效果原理也是类似的做法。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值