在之前的文章中咱们都是应用 <transition> 组件来实现过渡, 其次要用于单个节点、或同一时间渲染多个节点中的一个这两种状况。而对于整个列表(比方应用 v-for)的过渡,则须要应用本文介绍的 <transition-group> 组件。

四、列表过渡

1,<transition-group> 阐明

(1)不同于 <transition><transition-group> 会以一个实在元素出现:默认为一个 <span>(咱们能够通过 tag 个性更换为其余元素。)
(2)过渡模式不可用,因为咱们不再互相切换特有的元素。
(3)<transition-group> 的外部元素总是须要提供惟一的 key 属性值。

2,列表的进入、来到过渡

(1)效果图

  • 点击“插入一个元素”按钮,会在下方随机地位插入一个新的数字方块,新方块在插入过程中会有过渡动画。
  • 点击“移除一个元素”按钮,会随机删除下方的一个数字方块,该方块在移除过程中会有过渡动画。

(2)样例代码

<template>  <div id="app">    <div id="list-demo" class="demo">    <button v-on:click="add">插入一个元素</button>    <button v-on:click="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>  </div></template> <script>export default {  name: 'App',  data: function(){    return {      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)    },  }}</script> <style>  /** 方块元素的款式 **/  .list-item {    display: inline-block;    margin-right: 10px;    background-color: orange;    width: 30px;    height: 30px;    line-height: 30px;    text-align: center;    color: #ffffff;  }  /** 插入过程 **/  .list-enter-active{    transition: all 1s;  }  /** 移除过程 **/  .list-leave-active {    transition: all 1s;  }  /*** 开始插入、移除完结的地位变动 ***/  .list-enter, .list-leave-to {    opacity: 0;    transform: translateY(30px);  }</style>

3,列表的排序过渡

(1)下面的样例有个问题:尽管新插入的元素或者被移除的元素有动画成果,但它四周的元素会霎时挪动到他们新布局的地位,而不是平滑的过渡。要解决这个问题则须要借助新增的 v-move 个性。

v-move 个性会在元素扭转定位的过程中利用,它像之前的类名一样:能够通过 name 属性来自定义前缀(比方 name="xxxx",那么对应的类名便是 xxx-move)也能够通过 move-class 属性手动设置自定义类名。

(2)这里对之前样例的 css 局部稍作批改,能够发现在插入或移出过程中,其它元素也会从原来的地位平滑过渡新的地位。

<style>  /** 方块元素的款式 **/  .list-item {    display: inline-block;    margin-right: 10px;    background-color: orange;    width: 30px;    height: 30px;    line-height: 30px;    text-align: center;    color: #ffffff;  }  /** 插入过程 **/  .list-enter-active{    transition: all 1s;  }  /** 移除过程 **/  .list-leave-active {    transition: all 1s;    position: absolute;  }  /*** 开始插入、移除完结的地位变动 ***/  .list-enter, .list-leave-to {    opacity: 0;    transform: translateY(30px);  }  /*** 元素定位扭转时动画 ***/  .list-move {    transition: transform 1s;  }</style>

(3)Vue 应用了一个叫 FLIP 简略的动画队列实现排序过渡。所以即便没有插入或删除元素,对于元素程序的变动,也是反对过渡动画的。

<template>  <div id="app">    <div id="list-demo" class="demo">    <button v-on:click="shuffle">乱序</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>  </div></template> <script>export default {  name: 'App',  data: function(){    return {      items: [1,2,3,4,5,6,7,8,9]    }  },  methods: {    shuffle: function () {      return this.items.sort(function(a,b){ return Math.random()>.5 ? -1 : 1;})    }  }}</script> <style>  /** 方块元素的款式 **/  .list-item {    display: inline-block;    margin-right: 10px;    background-color: orange;    width: 30px;    height: 30px;    line-height: 30px;    text-align: center;    color: #ffffff;  }  /*** 元素定位扭转时动画 ***/  .list-move {    transition: transform 1s;  }</style>

(4)FLIP 动画不仅能够实现单列过渡,多维网格也同样能够过渡:

<template>  <div id="app">    <div id="list-demo" class="demo">    <button v-on:click="shuffle">乱序</button>    <transition-group name="cell" tag="div" class="container">      <div v-for="cell in cells" :key="cell.id" class="cell">        {{ cell.number }}      </div>    </transition-group>  </div>  </div></template> <script>export default {  name: 'App',  data: function(){    return {      cells: Array.apply(null, { length: 81 })        .map(function (_, index) {            return {            id: index,            number: index % 9 + 1          }        })    }  },  methods: {    shuffle: function () {      this.cells.sort(function(a,b){ return Math.random()>.5 ? -1 : 1;})    }  }}</script> <style>  .container {    display: flex;    flex-wrap: wrap;    width: 238px;    margin-top: 10px;  }  .cell {    display: flex;    justify-content: space-around;    align-items: center;    width: 25px;    height: 25px;    border: 1px solid #aaa;    margin-right: -1px;    margin-bottom: -1px;  }  .cell:nth-child(3n) {    margin-right: 0;  }  .cell:nth-child(27n) {    margin-bottom: 0;  }  .cell-move {    transition: transform 20s;  }</style>
附:应用 js 钩子函数实现列表的交织过渡

咱们也能够通过 data 属性与 JavaScript 通信,实现列表的交织过渡。

1,效果图

(1)在上方输入框中输出内容时,下方的列表会实时筛选并显示出蕴含该文字的条目。
(2)同时在列表条目标显示或者移出过程中,会有相应的过渡动画。

2,样例代码

<template>  <div id="app">    <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>  </div></template> <script>import  Velocity from 'velocity-animate' export default {  name: 'App',  data: function(){    return {      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, done) {      var delay = el.dataset.index * 150      setTimeout(function () {        Velocity(          el,          { opacity: 1, height: '1.6em' },          { complete: done , duration: 20000 }        )      }, delay)    },    leave: function (el, done) {      var delay = el.dataset.index * 150      setTimeout(function () {        Velocity(          el,          { opacity: 0, height: 0 },          { complete: done , duration: 20000 }        )      }, delay)    }  }}</script>