进入/离开&列表过渡总结

概述

vue在插入、更新或移除dom时,提供多种不同方法的应用过渡效果,包括以下工具:

(1)在css过渡和动画中自动应用class

(2)可以配合第三方css动画库,如animate.css

(3)在过渡钩子函数中使用javascript直接操作dom

(4)可以配合第三方javascript动画库,如velocity.js

单元素/组件的过渡

vue提供了transition的封装组件,在下列情形中,可以给任何元素和组件添加entering/leaving过渡

(1)条件渲染v-if

(2)条件展示v-show

(3)动态组件

(4)组件跟节点

例如:

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

当插入或删除包含在transition组件中的元素时,vue将会做以下处理

(1)自动嗅探目标元素是否应用了css过渡或动画,如果是,在恰当的时机添加、删除css类名

(2)如果过渡组件提供了javascript钩子函数,这些钩子函数将在恰当的时间被调用

(3)如果没有找到javascript钩子并且没有检测到css过渡、动画,dom操作在下一帧立即执行

1.过渡的类名

在进入、离开的过渡中,会有6个class切换

(1) v-enter :定义进入过渡的开始阶段,在元素被插入时生效,在下一帧移除

(2)v-enter-active:定义过渡的状态。在元素整个过渡过程中作用,在元素插入时生效,在transition/animation完成之后移除。这个类可以被用来定义过渡的过程时间,延迟和曲线函数

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

(4)v-leave:定义离开过渡的开始状态。在离开过渡过程中作用,在下一帧移除

(5)v-leave-active:定义过渡的状态。在元素整个过渡过程中作用,在离开过渡被触发后立即生效,在transition/animation完成之后移除。这个类可以被用来定义过渡的过程时间,延迟和曲线函数。

(6)v-leave-to:定义离开过渡的结束状态。在离开过渡被触发一帧后生效,在transition/animation完成后移除

css过渡

常用的过渡都是使用css过渡

<div id='example-1'>
  <button @click='show = !show'>
    Toggle Render
  </button>
  <transition name='slide-fade'>
    <p v-if='show'>hello</p>
  </transtion>
</div>
new Vue({
  el:'#example-1',
  data: {
    show: true
  }
})
.slide-fade-enter-active {
  transition: all 0.3s ease;
}
.slide-fade-leave-active {
  transition: all 0.8s cubic-bezier(1.0, 0.5, 0.8, 1.0)
}
.slide-fade-enter, .slide-fade-leave-to {
  transform: translateX(10px);
  opacity: 0
}

css动画

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

自定义过渡的类名

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

(1)enter-class

(2)enter-active-class

(3)enter-to-class

(4)leave-class

(5)leave-active-class

(6)leave-to-class

他们的优先级高于普通的类名,这对于vue的过渡系统和第三方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='anmated tada' leave-active-class='animated bounceOutRight'>
    <p v-if='show'>hello</p>
    </transition>
</div>
new Vue({
  el:'#example-3',
  data: {
    show: true
  }
})

同时使用过渡和动画

vue为了知道过渡的完成,必须设置相应的事件监听器。它可以是transitionend或animationend,这取决于给元素应用的css规则。如果你使用其中任何一种,vue能自动识别类型并设置监听。

但是,在一些场景中,你需要给同一个元素设置两种过渡效果,比如animation很快的被触发并完成了,而transition效果还没结束,这种情况下,你就需要使用type特性并设置animation或transition来明确声明你需要vue监听的类型

显性的过渡持续时间

在很多情况下,vue可以自动得出过渡效果的完成时机。默认情况下,vue会等待其在过渡效果的根元素的第一个transitionend或animationend事件,然而也可以不这样设定,比如,我们可以拥有一个精心编排的一序列过渡效果,其中一些嵌套的内部元素相比于过渡效果的根元素有延迟的或更长的过渡效果。

在这种情况下你可以用<transition>组件上的duration属性定制一个显性的过渡持续时间

<transition :duration='1000'>...</transition>

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

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

javascript钩子

<transition 
  v-on:before-enter='beforeEnter'
  v-on:enter = 'enter'
  v-on:after-enter = 'afterEnter'
  v-on:enter-cancelled='enterCancelled'

  v-on:before-leave='beforeLeave'
  v-on:leave='leave'
  v-on:after-leave='afterLeave'
  v-on:leave-cancelled='leaveCancelled'
>
</transition>
methods: {
  //进入中
  beforeEnter: function (el) {},
  //此回调函数是可选项的设置,与css结合时使用
  enter: function (el, done) {
    done()
  },
  afterEnter: function (el) {},
  enterCancelled: function (el) {},

  beforeLeave: function (el) {},
  leave: function (el, done) {
    done()
  },
  afterLeave: function (el) {},
  //leaveCancelled只用于v-show中
  leaveCancelled: function (el) {}
}

这些钩子函数可以结合css transitions/animations使用,也可以单独使用

当只用javascript过渡的时候,在enter和leave中,回调函数done是必须的,否则,他们会被同步调用,过渡会立即完成

推荐对于仅使用javascript过渡的元素,添加v-bind:css='false',vue会跳过检测

<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.opcity = 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 })
    }
  }
})

初始渲染的过渡

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

<transition appear></transition>

这里默认和进入离开过渡一样,同样可以自定义css类名

<transition 
  appear
  apper-class='custom-appear-class'
  appear-to-class='custom-appear-to-class'
  appear-active-class='custom-appear-active-class'>
</transition>
<transition
  appear
  v-on:before-appear = 'customBeforeAppearHook'
  v-on:appear='customAppearHook'
  v-on:after-appear='customAfterAppearHook'
  v-on:appear-cancelled='customAppearCacncelledHook'
>
</transition>

多个元素的过渡

<transition>
  <button v-bind:key='isEditing'>
    {{  isEditing ? 'save' : 'edit'}}
  </button>
</transition>
<transition>
  <button v-bind:key='docState'>
    {{ buttonMessage }}
  </button>
</transition>

new Vue({
  computed: {
    buttonMessage: function () {
      switch ( this.docState ) {
      case 'saved' : return 'edit'
      case 'edited' : return 'save'
      case 'editing' : return 'cancel'
      }
    }
  }
})

同时生效的进入和离开的过渡不能满足所有的要求,所有vue提供了过渡模式

(1)in-out:新元素先进行过渡,完成之后当前元素过渡离开

(2)out-in:当前元素先进行过渡,完成之后新元素过渡进入

mode='out-in'

多个组件的过渡

多个组件的过渡简单很多,我们不需要使用key特性,我们只需要使用动态组件

<transition name='component-fade' mode='out-in'>
  <component v-bind:is='view'></component>
</transition>
new Vue({
  el:'#transition',
  data: {
    view:'v-a'
  },
  components: {
    'v-a': {
      template: '<div>componentA</div>'
    },
    'v-b': {
      template: '<div>componentB</div>'
    }
  }
})
.component-fade-enter-active, .component-fade-leave-active {
  transition: opacity .3s ease;
}
.component-fade-enter, .component-fade-leave-to {
  opacity: 0
}

列表过渡

目前为止,关于过渡我们已经讲到:

(1)单个节点

(2)同一时间渲染多个节点中的一个

那么怎么同时渲染整个列表,比如使用v-for?在这种场景中,使用<transition-group>组件,这个组件的几个特点:

(1)不同于<transition>,它会以一个真实元素呈现,默认为一个span,你也可以通过tag特性更换为其他元素

(2)内部元素总是需要提过唯一的key属性值

列表的进入、离开过渡

<div id='list-demo' class='demo'>
  <button v-on:click='add'>Add</button>
  <button v-on:click='remove'>remove</button>
  <transition-group name='list' tag='p'>
    <span v-for='item in items' v-bind:key='item' class='list-item'>
     {{ item }}
    </span>
  </transition-group>
</div>
new Vue({
  el: '#list-demo',
  data: {
    items: [1,2,3,4,5,6,7,8,9],
    nextNum: 10
  },
  methods: {
    randomIndex: function () {
      return Math.floor(Math.random()*this.items.length),
    add: function () {
      this.items.splice(this.randomIndex(),0,this.nextNum++)
    },
    remove: function () {
   this.items.splice(this.randomIndex(),1)
    }
    }
  }
})
.list-style {
  display: inline-block;
  margin-right: 10px;
}
.list-enter-active, .list-leave-active {
  transition: all 1s
}
.list-enter, .list-leave-to {
  opacity: 0,
  transform: translateY(30px)
}

列表的排列过渡

<transition-group>组件还有一个特殊之处。不仅可以进入和离开动画,还可以改变定位。要使用这个新功能需要了解新增的v-move特性,它会在元素的改变定位过程中应用。像之前的类名一样,可以通过name属性来自定义前缀,也可以通过move-class属性手动设置

列表的交错过渡

通过data属性与javascript通信,就可以实现列表的交错过渡

<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>
<div id='staggered-list-demo'>
  <input v-model='query'>
  <transition-group
    name='staggered-fade'
    tag='ul'
    v-bind:css='false'
    v-on:before-enter='beforeEnter'
    v-on:enter='enter'
    v-on:leave='leave'
>
  <li
    v-for='(item, index) in computedList'
    v-bind:key='item.msg'
    v-bind:data-index='index'
>
  {{item.msg}}
  </li>
 </transition-group>
</div>
new Vue({
  el: '#staggered-list-demo',
  data: {
    query: '',
    list: [
      { msg: 'Bruce Lee' },
      { msg: 'Jackie Chan' },
      { msg: 'Chuck Norris' },
      { msg: 'Jet Li' },
      { msg: 'Kung Fury' }
    ]
  },
  computed: {
    computedList: function () {
      var vm = this;
      return this.list.filter(function (item) {
        return item.msg.toLowerCase().indexOf(vm.query.toLowerCase()) !==-1
})
    }
  },
  methods: {
    beforeEnter: function (el) {
      el.style.opacity = 0
      el.style.height = 0
    },
    enter: function (el) {
      var delay = el.dataset.index*150
      setTimeout(function () {
        Velocity(el, { opacity: 1, height: '1.6em'}, { complete: done})
      }, delay)
    },
    leave: function (el, done) {
      var delay = el.dataset.index*150
      setTimeout(function () {
        Velocity(el,{ opacity: 0, height: 0}, { complete: done})
      },delay)
    }
  }
})


阅读更多
想对作者说点什么? 我来说一句

Vue之过渡动画

Vue

tian361zyc tian361zyc

2017-06-08 21:24:52

阅读数:385

没有更多推荐了,返回首页

不良信息举报

进入/离开&列表过渡总结

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭