文章出處

前面的話

  本文將詳細介紹Vue列表過渡

 

概述

  前面分別介紹了單元素CSS過渡JS過渡,以及多元素過渡。如何同時渲染整個列表呢?在這種情景中,需要使用<transition-group>組件

【<transition-group>】

  <transition-group>不同于 <transition>, 它會以一個真實元素呈現:默認為一個 <span>。也可以通過 tag 特性更換為其他元素。而且其內部元素總是需要提供唯一的 key 屬性值

<transition-group name="list" tag="p">
    <!-- ... -->
  </transition-group>

 

普通過渡

  下面是一個添加和刪除列表項的例子

<style>
.list-item {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);}
</style>
<div id="list-demo" class="demo">
  <button @click="add">Add</button>
  <button @click="remove">Remove</button>
  <transition-group name="list" tag="p">
    <span v-for="item in items" :key="item" class="list-item">{{item}}</span>
  </transition-group>
</div>
<script>
new Vue({
  el: '#list-demo',
  data: {
    items: [1,2,3,4,5,6,7,8,9],
    nextNum: 10
  },
  methods: {
    randomIndex() {
      return Math.floor(Math.random() * this.items.length)
    },
    add() {
      this.items.splice(this.randomIndex(), 0, this.nextNum++)
    },
    remove() {
      this.items.splice(this.randomIndex(), 1)
    },
  }
})
</script>

 

平滑過渡

  上面這個例子有個問題,當添加和移除元素的時候,周圍的元素會瞬間移動到他們的新布局的位置,而不是平滑的過渡

【v-move】

  <transition-group> 組件還有一個特殊之處。不僅可以進入和離開動畫,還可以改變定位。要使用這個新功能只需了解新增的 v-move 特性,它會在元素的改變定位的過程中應用。像之前的類名一樣,可以通過 name 屬性來自定義前綴,也可以通過 move-class 屬性手動設置

  在上面代碼中基礎上,做出如下改進:

  1、增加.list-move的樣式,使元素在進入時實現過渡效果

  2、在.list-leave-active中設置絕對定位,使元素在離開時實現過渡效果

<style>
.list-item {display: inline-block;margin-right: 10px;}
.list-move,.list-enter-active, .list-leave-active {transition: 1s;}
.list-leave-active{position:absolute;}
.list-enter, .list-leave-to{opacity: 0;transform: translateY(30px);}
</style>

 

變換過渡

  下面接著利用move屬性,進行變換過渡,即一個列表中的列表項既不增加也不減少,只是不斷地變換其位置

<style>
.list-move{transition: transform 1s;}
</style>
<div id="list-demo" class="demo">
  <button @click="shuffle">shuffle</button>
  <transition-group name="list" tag="ul">
    <li v-for="item in items" :key="item">{{item}}</li>
  </transition-group>
</div>
<script>
new Vue({
  el: '#list-demo',
  data: {
    items: [1,2,3,4,5,6,7,8,9],
  },
  methods: {
    shuffle(){
      this.items = this.items.sort(()=>{return Math.random() - 0.5;})
    },
  }
})
</script>

  下面的效果看起來很神奇,內部的實現,Vue 使用了一個叫 FLIP 簡單的動畫隊列,使用 transforms 將元素從之前的位置平滑過渡新的位置

  下面將進入離開的例子和這個技術結合, 使列表的一切變動都會有動畫過渡

  [注意]使用 FLIP 過渡的元素不能設置為 display: inline 。作為替代方案,可以設置為 display: inline-block 或者放置于 flex 中

<style>
.list-item {display: inline-block;margin-right: 10px;}
.list-move,.list-enter-active, .list-leave-active {transition: 1s;}
.list-leave-active{position:absolute;}
.list-enter, .list-leave-to{opacity: 0;transform: translateY(30px);}
</style>

  以上代碼中,由于move、enter和leave都需要設置transition。因此,直接在元素上設置transition即可

<style>
.list-item {display: inline-block;margin-right: 10px;transition: 1s;}
.list-leave-active{position:absolute;}
.list-enter, .list-leave-to{opacity: 0;transform: translateY(30px);}
</style>

  下面是完整代碼

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
.list-item {display: inline-block;margin-right: 10px;transition: 1s;}
.list-leave-active{position:absolute;}
.list-enter, .list-leave-to{opacity: 0;transform: translateY(30px);}
</style>
</head>
<body>
<div id="list-demo" class="demo">
  <button @click="shuffle">shuffle</button>
  <button @click="add">Add</button>
  <button @click="remove">Remove</button>  
  <transition-group name="list" tag="p">
    <span v-for="item in items" :key="item" class="list-item">{{item}}</span>
  </transition-group>
</div>
<script type="text/javascript" src="http://sandbox.runjs.cn/uploads/rs/26/ddzmgynp/vue.js"></script>
<script>
new Vue({
  el: '#list-demo',
  data: {
    items: [1,2,3,4,5,6,7,8,9],
    nextNum: 10
  },
  methods: {
    randomIndex() {
      return Math.floor(Math.random() * this.items.length)
    },
    add() {
      this.items.splice(this.randomIndex(), 0, this.nextNum++)
    },
    remove() {
      this.items.splice(this.randomIndex(), 1)
    },    
    shuffle(){
      this.items = this.items.sort(()=>{return Math.random() - 0.5;})
    },
  }
})
</script>
</body>
</html>

 

多維列表

  FLIP 動畫不僅可以實現單列過渡,多維網格的過渡也同樣簡單

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
.container {width: 270px;margin-top: 10px;line-height:30px;text-align:center;}
.cell {display: inline-block;width: 30px;height: 30px;outline: 1px solid #aaa;}
.cell-move {transition:1s;}
</style>
</head>
<body>
<div id="list-demo" class="demo">
  <button @click="shuffle">shuffle</button>
  <transition-group name="cell" tag="div" class="container">
    <span v-for="cell in cells" :key="cell.id" class="cell">{{ cell.number }}</span>
  </transition-group>
</div>
<script type="text/javascript" src="http://sandbox.runjs.cn/uploads/rs/26/ddzmgynp/vue.js"></script>
<script>
new Vue({
  el: '#list-demo',
   data: {
      cells: Array.apply(null, { length: 81 })
        .map(function (_, index) { 
          return {
            id: index,
            number: index % 9 + 1
          }
        })
    },
  methods: {
    shuffle(){
      this.cells = this.cells.sort(()=>{return Math.random() - 0.5;})
    },
  }
})
</script>
</body>
</html>

 

漸進過渡

  通過 data 屬性與 JavaScript 通信 ,就可以實現列表的漸進過渡

  下面是使用CSS過渡實現的一個例子

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
.list-move,.list-enter-active, .list-leave-active {transition: 1s;}
.list-leave-active{position:absolute;}
.list-enter,.list-leave-to{opacity: 0;height:0;}
</style>
</head>
<body>
<div id="list-demo" class="demo">
  <input v-model="query">
  <transition-group name="list" tag="ul">
    <li v-for="(item, index) in computedList" :key="item" :data-index="index">{{item}}</li>
  </transition-group>
</div>
<script type="text/javascript" src="http://sandbox.runjs.cn/uploads/rs/26/ddzmgynp/vue.js"></script>
<script>
new Vue({
  el: '#list-demo',
  data: {
    query: '',
    list: ['HTML','CSS','Javascript','jQuery','Vue']
  },
  computed: {
    computedList() {
      return this.list.filter((item)=>{
        return item.toLowerCase().indexOf(this.query.toLowerCase()) !== -1
      })
    }
  },  
})
</script>
</body>
</html>

  上面的效果中,列表項是一齊運動的。如果要實現依次運動的效果,則需要使用JS過渡來實現

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="list-demo" class="demo">
  <input v-model="query">
  <transition-group name="list" tag="ul" :css="false" @before-enter="beforeEnter" @enter="enter" @leave="leave">
    <li v-for="(item, index) in computedList" :key="item" :data-index="index">{{item}}</li>
  </transition-group>
</div>
<script type="text/javascript" src="http://sandbox.runjs.cn/uploads/rs/26/ddzmgynp/velocity.min.js"></script>
<script type="text/javascript" src="http://sandbox.runjs.cn/uploads/rs/26/ddzmgynp/vue.js"></script>
<script>
new Vue({
  el: '#list-demo',
  data: {
    query: '',
    list: ['HTML','CSS','Javascript','jQuery','Vue']
  },
  computed: {
    computedList() {
      return this.list.filter((item)=>{
        return item.toLowerCase().indexOf(this.query.toLowerCase()) !== -1
      })
    }
  },  
  methods: {
    beforeEnter(el) {
      el.style.opacity = el.style.height = 0
    },
    enter(el, done) {
      setTimeout(()=>{
        Velocity(el,{ opacity: 1, height: '1.6em' },{ complete: done })
      }, el.dataset.index * 150)
    },
    leave(el, done) {
      setTimeout(()=>{
        Velocity(el,{ opacity: 0, height: 0 },{ complete: done })
      }, el.dataset.index * 150)
    }
  },  
})
</script>
</body>
</html>

 


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()