乐趣区

关于前端:Vue2-Transition过渡动画的使用4使用transitiongroup实现列表过渡

  在之前的文章中咱们都是应用 <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>
退出移动版