【VUE】Transition实现多元素/多组件的过渡效果

1,691 阅读1分钟

这是我参与8月更文挑战的第23天,活动详情查看:8月更文挑战

多元素的过渡

  1. 对于原生标签我们可以使用 v-if/v-else 实现多元素过渡。比如实现一个 点击 切换 前后出现 两个元素。
<style type="text/css">
        .v-enter, .v-leave-to {
                opacity: 0;
        }
        .v-enter-active,.v-leave-active {
                transition: opacity 1s; 
        }
</style>
<div id="app">
    <button type="button" @click="handleToggle">切换显隐</button>
    <transition>
            <div v-if="show" >初始内容</div>
            <div v-else >切换内容</div>
    </transition>
</div>
var vm = new Vue({
    el: '#app',
    data: function() {
        return {
                show: true
        }
    },
    methods:{
        handleToggle: function() {
                this.show = !this.show
        }
    }
})

上述代码执行后,发现css定义的动画效果没有实现,这是因为要给相同标签名的元素增加 key属性。

  1. 如果有两个以上的元素过渡可以这么写:

注意:当有相同标签名的元素切换时,需要通过 key attribute 设置唯一的值来标记以让 Vue 区分它们,否则 Vue 为了效率只会替换相同标签内部的内容。即使在技术上没有必要,给在 <transition> 组件中的多个元素设置 key 是一个更好的实践。

<transition>
  <button v-if="docState === 'saved'" key="saved">
    Edit
  </button>
  <button v-if="docState === 'edited'" key="edited">
    Save
  </button>
  <button v-if="docState === 'editing'" key="editing">
    Cancel
  </button>
</transition>
  1. 在一些场景中,也可以通过给同一个元素的 key 特性设置不同的状态来代替 v-if 和 v-else
<transition>
  <button v-bind:key="docState">
    {{ buttonMessage }}
  </button>
</transition>
computed: {
  buttonMessage: function () {
    switch (this.docState) {
      case 'saved': return 'Edit'
      case 'edited': return 'Save'
      case 'editing': return 'Cancel'
    }
  }
}

过渡模式mode="in-out"

Vue 提供了过渡模式,来解决进入和离开的的过渡顺序。其中:

  • in-out:新元素先进行过渡,完成之后当前元素过渡离开。
  • out-in:当前元素先进行过渡,完成之后新元素过渡进入。

多组件的过渡

多个组件的过渡简单很多 - 我们不需要使用 key attribute。相反,我们只需要使用动态组件

使用  <component :is="type"> 的动态组件实现

<button type="button" @click="handleClick">切换组件</button>
<component :is="type"></component>
data: function() {
    return {
        show: true,
        type: 'child-one'
    }
},
handleClick: function() {
    this.type = this.type === 'child-one' ? 'child-two': 'child-one'
}