閱讀986 返回首頁    go 阿裏雲 go 技術社區[雲棲]


過渡和動畫

進入/離開 & 列表過渡

概述

Vue在插入、更新或移除DOM時,提供多種不同方式的應用過渡效果。包括以下工具:

在CSS過渡和動畫中自動應用class;配合使用第三方CSS動畫庫,如Animate.css;在過渡鉤子函數中使用JavaScript直接操作DOM;配合使用第三方JavaScript動畫庫,如Velocity.js

在這裏,我們隻會講到進入、離開和列表的過渡, 你也可以看下一節的管理過渡狀態

單元素/組件的過渡

Vue提供了transition的封裝組件,在下列情形中,可以給任何元素和組件添加entering/leaving過渡

條件渲染(使用 v-if);條件展示(使用 v-show);動態組件;組件根節點

這裏是一個典型的例子:

<div >
  <button v-on:click="show = !show"> Toggle </button>
  <transition name="fade">
    <p v-if="show">hello</p>
  </transition>
</div>
<script>
new Vue({
  el: '#demo',
  data: {
    show: true
  }
})
</script>
<style>
.fade-enter-active, .fade-leave-active { transition: opacity .5s }
.fade-enter, .fade-leave-to /* .fade-leave-active in below version 2.1.8 */ { opacity: 0 </style>

當插入或刪除包含在transition組件中的元素時,Vue將會做以下處理:

1.自動嗅探目標元素是否應用了CSS過渡或動畫,如果是,在恰當的時機添加/刪除CSS類名

2.如果過渡組件提供了JavaScript鉤子函數,這些鉤子函數將在恰當的時機被調用

3.如果沒有找到JavaScript鉤子並且也沒有檢測到CSS過渡/動畫,DOM 操作(插入/刪除)在下一幀中立即執行。(注意:此指瀏覽器逐幀動畫機製,和Vue的nextTick概念不同)

過渡的類名

在進入/離開的過渡中,會有6個class切換

1.v-enter: 定義進入過渡的開始狀態。在元素被插入時生效,在下一個幀移除

2.v-enter-active: 定義過渡的狀態。在元素整個過渡過程中作用,在元素被插入時生效,在transition/animation完成之後移除。 這個類可以被用來定義過渡的過程時間,延遲和曲線函數。

3.v-enter-to: 2.1.8版及以上定義進入過渡的結束狀態。在元素被插入一幀後生效(於此同時v-enter被刪除),在transition/animation完成之後移除

4.v-leave: 定義離開過渡的開始狀態。在離開過渡被觸發時生效,在下一個幀移除

5.v-leave-active: 定義過渡的狀態。在元素整個過渡過程中作用,在離開過渡被觸發後立即生效,在 transition/animation 完成之後移除。 這個類可以被用來定義過渡的過程時間,延遲和曲線函數。

6.v-leave-to: 2.1.8版及以上定義離開過渡的結束狀態。在離開過渡被觸發一幀後生效(於此同時v-leave被刪除),在transition/animation完成之後移除

對於這些在enter/leave過渡中切換的類名,v-是這些類名的前綴。使用可以重置前綴,比如v-enter替換為my-transition-enter

v-enter-active和v-leave-active可以控製進入/離開過渡的不同階段,在下麵章節會有示例說明

css過渡

常用的過渡都是使用CSS過渡,舉例如下:

<div >
  <button @click="show = !show">
    Toggle render
  </button>
  <transition name="slide-fade">
    <p v-if="show">hello</p>
  </transition>
</div>
<script>
  new Vue({
    el: '#example-1',
    data: {
      show: true
    }
  })
</script>
<style>
  .slide-fade-enter-active {
    transition: all .3s ease;
  }
  .slide-fade-leave-active {
    transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0);
  }
  .slide-fade-enter, .slide-fade-leave-to /* .slide-fade-leave-active for below version 2.1.8 */ {
    transform: translateX(10px);
    opacity: 0;
  }
</style>

css動畫

CSS動畫同CSS過渡,區別在動畫中v-enter類名在節點插入DOM後不會立即刪除,而是在animationend事件觸發時刪除,示例:

<div >
  <button @click="show = !show">Toggle show</button>
  <transition name="bounce">
    <p v-if="show">Look at me!</p>
  </transition>
</div>
<script>
  new Vue({
    el: '#example-2',
    data: {
      show: true
    }
  })
</script>
<style>
  .bounce-enter-active {
    animation: bounce-in .5s;
  }
  .bounce-leave-active {
    animation: bounce-in .5s reverse;
  }
  @keyframes bounce-in {
    0% {
      transform: scale(0);
    }
    50% {
      transform: scale(1.5);
    }
    100% {
      transform: scale(1);
    }
  }
</style>

自定義過渡的類名

我們可以通過以下特性來自定義過渡類名:

enter-class/enter-active-class/enter-to-class (2.1.8+)/leave-class/leave-active-class/leave-to-class (2.1.8+)

他們的優先級高於普通的類名,這對於Vue的過渡係統和其他第三方CSS動畫庫,如Animate.css結合使用十分有用,示例:

<link href="https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel="stylesheet" type="text/css">
<div >
  <button @click="show = !show"> Toggle render </button>
  <transition name="custom-classes-transition" enter-active- leave-active->
    <p v-if="show">hello</p>
  </transition>
</div>
<script>
  new Vue({
    el: '#example-3',
    data: {
      show: true
    }
  })
</script>

同時使用過渡和動畫

Vue為了知道過渡的完成,必須設置相應的事件監聽器。它可以是transitionend或animationend,這取決於給元素應用的CSS規則。如果使用其中任何一種,Vue能自動識別類型並設置監聽。但是,在一些場景中,你需要給同一個元素同時設置兩種過渡動效,比如animation很快的被觸發並完成了,而transition效果還沒結束。在這種情況中,你需要使用type特性並設置animation或transition來明確聲明你需要Vue監聽的類型

顯性的過渡持續時間

很多情況下,Vue可以自動得出過渡效果的完成時機。默認情況下,Vue會等待其在過渡效果的根元素的第一個transitionend或animationend事件。然而也可以不這樣設定——比如:我們可以擁有一個精心編排的一序列過渡效果,其中一些嵌套的內部元素相比於過渡效果的根元素有延遲的或更長的過渡效果。在這種情況下你可以用組件上的duration屬性定製一個顯性的過渡持續時間(以毫秒計):

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

你也可以定製進入和移出的持續時間:

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

JavaScript鉤子

可以在屬性中聲明 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>
<script>
  // ...
  methods: {
    // 進入中
    beforeEnter: function (el) {
      // ...
    },
    // 此回調函數是可選項的設置,與CSS結合時使用
    enter: function (el, done) {
      // ...
      done()
    },
    afterEnter: function (el) {
      // ...
    },
    enterCancelled: function (el) {
      // ...
    },
    // 離開時
    beforeLeave: function (el) {
      // ...
    },
    // 此回調函數是可選項的設置,與CSS結合時使用
    leave: function (el, done) {
      // ...
      done()
    },
    afterLeave: function (el) {
      // ...
    },
    // leaveCancelled 隻用於 v-show 中
    leaveCancelled: function (el) {
      // ...
    }
  }
</script>

這些鉤子函數可以結合CSS的transitions/animations使用,也可以單獨使用

當隻用JavaScript過渡時,在enter和leave中,回調函數done是必須的。否則,它們會被同步調用,過渡會立即完成。

推薦對於僅使用JavaScript過渡的元素添加v-bind:css="false",Vue會跳過CSS的檢測。這也可以避免過渡過程中CSS的影響

一個使用 Velocity.js 的簡單例子:

<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>
<div >
  <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>
<script>
  new Vue({
    el: '#example-4',
    data: {
      show: false
    },
    methods: {
      beforeEnter: function (el) {
        el.style.opacity = 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 })
      }
    }
  })
</script>

初始渲染的過渡

可以通過appear特性設置節點的在初始渲染的過渡

<transition appear>
  <!-- ... -->
</transition>

這裏默認和進入和離開過渡一樣,同樣也可以自定義 CSS 類名

<transition appear appear- appear-to- (2.1.8+) appear-active- >
  <!-- ... -->
</transition>

自定義 JavaScript 鉤子:

<transition appear v-on:before-appear="customBeforeAppearHook" v-on:appear="customAppearHook" v-on:after-appear="customAfterAppearHook" v-on:appear-cancelled="customAppearCancelledHook" >
  <!-- ... -->
</transition>

多個元素的過渡

對於原生標簽可以使用v-if/v-else。最常見的多標簽過渡是一個列表和描述這個列表為空消息的元素:

<transition>
  <table v-if="items.length > 0">
    <!-- ... -->
  </table>
  <p v-else>Sorry, no items found.</p>
</transition>

可以這樣使用,但是有一點需要注意:當有相同標簽名的元素切換時,需要通過key特性設置唯一的值來標記以讓Vue區分它們,否則Vue為了效率隻會替換相同標簽內部的內容。即使在技術上沒有必要,給在組件中的多個元素設置key是一個更好的實踐

<transition>
  <button v-if="isEditing" key="save"> Save </button>
  <button v-else key="edit"> Edit </button>
</transition>

在一些場景中,也可以通過給同一個元素的key特性設置不同狀態來代替v-if和v-else,上麵的例子可以重寫為:

<transition>
  <button v-bind:key="isEditing"> {{ isEditing ? 'Save' : 'Edit' }} </button>
</transition>

使用多個v-if的多個元素的過渡可以重寫為綁定了動態屬性的單個元素過渡。 例如:

<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>

可以重寫為:

<transition>
  <button v-bind:key="docState"> {{ buttonMessage }} </button>
</transition>
<script>
  computed: {
    buttonMessage: function () {
      switch (this.docState) {
        case 'saved': return 'Edit'
        case 'edited': return 'Save'
        case 'editing': return 'Cancel'
      }
    }
  }
</script>

過渡模式

在“on”按鈕和“off”按鈕的過渡中,兩個按鈕都被重繪了,一個離開過渡的時候另一個開始進入過渡。這是 的默認行為 - 進入和離開同時發生。

同時生效的進入和離開的過渡不能滿足所有要求,所以Vue提供了過渡模式

in-out: 新元素先進行過渡,完成之後當前元素過渡離開

out-in: 當前元素先進行過渡,完成之後新元素過渡進入

用out-in重寫之前的開關按鈕過渡:

<transition name="fade" mode="out-in">
  <!-- ... the buttons ... -->
</transition>

隻用添加一個簡單的特性,就解決了之前的過渡問題而無需任何額外的代碼。in-out

多個組件的過渡

多個組件的過渡簡單很多 - 我們不需要使用 key 特性。相反,我們隻需要使用動態組件:

<transition name="component-fade" mode="out-in">
  <component v-bind:is="view"></component>
</transition>
<script>
  new Vue({
    el: '#transition-components-demo',
    data: {
      view: 'v-a'
    },
    components: {
      'v-a': {
        template: '<div>Component A</div>'
      },
      'v-b': {
        template: '<div>Component B</div>'
      }
    }
  }) 
</script>
<style>
   .component-fade-enter-active, .component-fade-leave-active {
      transition: opacity .3s ease;
    }
    .component-fade-enter, .component-fade-leave-to /* .component-fade-leave-active for below version 2.1.8 */ {
      opacity: 0;
    }
</style>

列表過渡

目前為止,關於過渡我們已經講到:

1.單個節點

2.同一時間渲染多個節點中的一個

那麼怎麼同時渲染整個列表,比如使用v-for?這種場景中使用組件。我們先了解關於這個組件的幾個特點:

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

列表的進入/離開過渡

現在讓我們由一個簡單的例子深入,進入和離開的過渡使用之前一樣的CSS類名

<div  >
  <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" >
      {{ 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: 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;
  }
  .list-enter-active, .list-leave-active {
    transition: all 1s;
  }
  .list-enter, .list-leave-to /* .list-leave-active for below version 2.1.8 */ {
    opacity: 0; transform: translateY(30px);
  }
</style>

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

列表的排序過渡

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

v-move對於設置過渡的切換時機和過渡曲線非常有用,你會看到如下的例子:

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.14.1/lodash.min.js"></script>
<div  >
  <button v-on:click="shuffle">Shuffle</button>
  <transition-group name="flip-list" tag="ul">
    <li v-for="item in items" v-bind:key="item"> {{ item }} </li>
  </transition-group>
</div>
<script>
  new Vue({
    el: '#flip-list-demo',
    data: {
      items: [1,2,3,4,5,6,7,8,9]
    },
    methods: {
      shuffle: function () {
        this.items = _.shuffle(this.items)
      }
    }
  })
</script>
<style>
  .flip-list-move {
    transition: transform 1s;
  }
</style>

這個看起來很神奇,內部的實現,Vue 使用了一個叫FLIP簡單的動畫隊列;使用transforms將元素從之前的位置平滑過渡新的位置。我們將之前實現的例子和這個技術結合,使我們列表的一切變動都會有動畫過渡

<script>
  new Vue({
    el: '#list-complete-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)
      },
      shuffle: function () {
        this.items = _.shuffle(this.items)
      }
    }
  })
</script>
<style>
  .list-complete-item {
    transition: all 1s; display: inline-block; margin-right: 10px;
  }
  .list-complete-enter, .list-complete-leave-to /* .list-complete-leave-active for below version 2.1.8 */ {
    opacity: 0; transform: translateY(30px);
  }
  .list-complete-leave-active {
    position: absolute;
  }
</style>

需要注意的是使用FLIP過渡的元素不能設置為display: inline。可以設置為display:inline-block或置於flex中

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

列表的交錯過渡

通過data屬性與JavaScript通信 ,就可以實現列表的交錯過渡:

<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>
<div >
  <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>
<script>
  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, done) {
        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)
      }
    }
  })
</script>

可複用的過渡

過渡可以通過Vue的組件係統實現複用。要創建一個可複用過渡組件,需要做的就是將或 作為根組件,然後將任何子組件放置在其中就可以了

使用 template 的簡單例子:

Vue.component('my-special-transition', {
  template: '\
    <transition name="very-special-transition" mode="out-in" v-on:before-enter="beforeEnter" v-on:after-enter="afterEnter" >\
      <slot></slot>\
    </transition>\
  ',
  methods: {
    beforeEnter: function (el) {
      // ...
    },
    afterEnter: function (el) {
      // ...
    }
  }
})

函數組件更適合完成這個任務:

Vue.component('my-special-transition', {
  functional: true,
  render: function (createElement, context) {
    var data = {
      props: {
        name: 'very-special-transition',
        mode: 'out-in'
      },
      on: {
        beforeEnter: function (el) {
          // ...
        },
        afterEnter: function (el) {
          // ...
        }
      }
    }
    return createElement('transition', data, context.children)
  }
})

動態過渡

在Vue中即使是過渡也是數據驅動的!動態過渡最基本的例子是通過 name 特性來綁定動態值

<transition v-bind:name="transitionName">
  <!-- ... -->
</transition>

當你想用Vue的過渡係統來定義CSS過渡/動畫在不同過渡間切換會非常有用。所有的過渡特性都是動態綁定的。它不僅是簡單的特性,通過事件的鉤子函數方法,可以在獲取到相應上下文數據。這意味著,可以根據組件的狀態通過JS過渡設置不同的過渡效果

<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>
<div  >
  Fade In: <input type="range" v-model="fadeInDuration" min="0" v-bind:max="maxFadeDuration">
  Fade Out: <input type="range" v-model="fadeOutDuration" min="0" v-bind:max="maxFadeDuration">
  <transition v-bind:css="false" v-on:before-enter="beforeEnter" v-on:enter="enter" v-on:leave="leave" >
    <p v-if="show">hello</p>
  </transition>
  <button v-if="stop" v-on:click="stop = false; show = false" >Start animating</button>
  <button v-else v-on:click="stop = true" >Stop it!</button>
</div>
<script>
  new Vue({
    el: '#dynamic-fade-demo',
    data: {
      show: true,
      fadeInDuration: 1000,
      fadeOutDuration: 1000,
      maxFadeDuration: 1500,
      stop: true
    },
    mounted: function () {
      this.show = false
    },
    methods: {
      beforeEnter: function (el) {
        el.style.opacity = 0
      },
      enter: function (el, done) {
        var vm = this
        Velocity(el,
          { opacity: 1 },
          {
            duration: this.fadeInDuration,
            complete: function () {
              done()
              if (!vm.stop) vm.show = false
            }
          }
        )
      },
      leave: function (el, done) {
        var vm = this
        Velocity(el,
          { opacity: 0 },
          {
            duration: this.fadeOutDuration,
            complete: function () {
              done()
              vm.show = true
            }
          }
        )
      }
    }
  })
</script>

最後,創建動態過渡的最終方案是組件通過接受 props 來動態修改之前的過渡。一句老話,唯一的限製是你的想象力

過渡狀態

Vue的過渡係統提供了非常多簡單的方法設置進入、離開和列表的動效。那麼對於數據元素本身的動效呢,比如:數字和運算、顏色的顯示、SVG節點的位置、元素的大小和其他的屬性

所有的原始數字都被事先存儲起來,可以直接轉換到數字。做到這一步,我們就可以結合Vue的響應式和組件係統,使用第三方庫來實現切換元素的過渡狀態

狀態動畫與觀察者

通過觀察者我們能監聽到任何數值屬性的數值更新。可能聽起來很抽象,所以讓我們先來看看使用Tweenjs一個例子:

<script src="https://cdn.jsdelivr.net/npm/tween.js@16.3.4"></script>
<div >
  <input v-model.number="number" type="number" step="20">
  <p>{{ animatedNumber }}</p>
</div>
<script>
  new Vue({
    el: '#animated-number-demo',
    data: {
      number: 0,
      animatedNumber: 0
    },
    watch: {
      number: function(newValue, oldValue) {
        var vm = this
        function animate () {
          if (TWEEN.update()) {
            requestAnimationFrame(animate)
          }
        }
        new TWEEN.Tween({ tweeningNumber: oldValue }).easing(TWEEN.Easing.Quadratic.Out).to({ tweeningNumber: newValue }, 500).onUpdate(function () {
            vm.animatedNumber = this.tweeningNumber.toFixed(0)
          })
          .start()
        animate()
      }
    }
  })
</script>

當你把數值更新時,就會觸發動畫。這個是一個不錯的演示,但是對於不能直接像數字一樣存儲的值,比如 CSS 中的 color 的值,通過下麵的例子我們來通過 Color.js 實現一個例子:

<script src="https://cdn.jsdelivr.net/npm/tween.js@16.3.4"></script>
<script src="https://cdn.jsdelivr.net/npm/color-js@1.0.3"></script>
<div >
  <input v-model="colorQuery" v-on:keyup.enter="updateColor" placeholder="Enter a color" >
  <button v-on:click="updateColor">Update</button>
  <p>Preview:</p>
  <span v-bind:  ></span>
  <p>{{ tweenedCSSColor }}</p>
</div>
<script>
  var Color = net.brehaut.Color
  new Vue({
    el: '#example-7',
    data: {
      colorQuery: '',
      color: {
        red: 0,
        green: 0,
        blue: 0,
        alpha: 1
      },
      tweenedColor: {}
    },
    created: function () {
      this.tweenedColor = Object.assign({}, this.color)
    },
    watch: {
      color: function () {
        function animate () {
          if (TWEEN.update()) {
            requestAnimationFrame(animate)
          }
        }
        new TWEEN.Tween(this.tweenedColor).to(this.color, 750).start()
        animate()
      }
    },
    computed: {
      tweenedCSSColor: function () {
        return new Color({
          red: this.tweenedColor.red,
          green: this.tweenedColor.green,
          blue: this.tweenedColor.blue,
          alpha: this.tweenedColor.alpha
        }).toCSS()
      }
    },
    methods: {
      updateColor: function () {
        this.color = new Color(this.colorQuery).toRGB()
        this.colorQuery = ''
      }
    }
  })
</script>
<style>
  .example-7-color-preview {
    display: inline-block; width: 50px; height: 50px;
  }
</style>

動畫狀態過渡

就像Vue的過渡組件一樣,數據背後狀態過渡會實時更新,這對於原型設計十分有用。當你修改一些變量,即使是一個簡單的SVG多邊形也可實現很多難以想象的效果

把過渡放到組件裏

管理太多的狀態過渡會很快的增加Vue實例或者組件的複雜性,幸好很多的動畫可以提取到專用的子組件。我們來將之前的示例改寫一下:

<script src="https://cdn.jsdelivr.net/npm/tween.js@16.3.4"></script>
<div >
  <input v-model.number="firstNumber" type="number" step="20"> +
  <input v-model.number="secondNumber" type="number" step="20"> =
  {{ result }}
  <p>
    <animated-integer v-bind:value="firstNumber"></animated-integer> +
    <animated-integer v-bind:value="secondNumber"></animated-integer> =
    <animated-integer v-bind:value="result"></animated-integer>
  </p>
</div>
<script>
  //複雜的補間動畫邏輯可以被複用,任何整數都能執行動畫,組件化使界麵十分清晰,支持更多更複雜的動態過渡策略
  Vue.component('animated-integer', {
    template: '<span>{{ tweeningValue }}</span>',
    props: {
      value: {
        type: Number,
        required: true
      }
    },
    data: function () {
      return {
        tweeningValue: 0
      }
    },
    watch: {
      value: function (newValue, oldValue) {
        this.tween(oldValue, newValue)
      }
    },
    mounted: function () {
      this.tween(0, this.value)
    },
    methods: {
      tween: function (startValue, endValue) {
        var vm = this
        function animate () {
          if (TWEEN.update()) {
            requestAnimationFrame(animate)
          }
        }
        new TWEEN.Tween({ tweeningValue: startValue })
          .to({ tweeningValue: endValue }, 500)
          .onUpdate(function () {
            vm.tweeningValue = this.tweeningValue.toFixed(0)
          })
          .start()
        animate()
      }
    }
  })
  // 所有的複雜度都已經從 Vue 的主實例中移除!
  new Vue({
    el: '#example-8',
    data: {
      firstNumber: 20,
      secondNumber: 40
    },
    computed: {
      result: function () {
        return this.firstNumber + this.secondNumber
      }
    }
  })
</script>

我們能在組件中結合使用這裏提到各種過渡策略和Vue內建的過渡係統。總之,對於完成各種過渡動效幾乎沒有阻礙

賦予設計以生命

SVG的本質是數據,我們隻需要這些動物興奮、思考或境界的樣例。然後Vue就可以輔助完成這幾種狀態之間的過渡動畫,來製作你的歡迎頁麵、加載指示、以及更加帶有情感的提示

最後更新:2017-09-11 22:03:45

  上一篇:go  去哪兒網基於Mesos和Docker構建私有雲服務的實踐
  下一篇:go  大數據揭秘:男人養狗脫單,女人養狗落單