vue中过渡和动画

简介: .fade-enter-active, .fade-leave-active { transition: opacity .5s } .fade-enter, .fade-leave-to /* .fade-leave-active in below version 2.

进入/离开 & 列表过渡

概述

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

在CSS过渡和动画中自动应用class;配合使用第三方CSS动画库,如Animate.css;在过渡钩子函数中使用JavaScript直接操作DOM;配合使用第三方JavaScript动画库,如Velocity.js

在这里,我们只会讲到进入、离开和列表的过渡, 你也可以看下一节的管理过渡状态

单元素/组件的过渡

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

条件渲染(使用 v-if);条件展示(使用 v-show);动态组件;组件根节点

这里是一个典型的例子:

<div id="demo">
  <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 id="example-1">
  <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 id="example-2">
  <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 id="example-3">
  <button @click="show = !show"> Toggle render </button>
  <transition name="custom-classes-transition" enter-active-class="animated tada" leave-active-class="animated bounceOutRight">
    <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 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>
<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-class="custom-appear-class" appear-to-class="custom-appear-to-class" (2.1.8+) appear-active-class="custom-appear-active-class" >
  <!-- ... -->
</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 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>
<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 id="flip-list-demo" class="demo">
  <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 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>
<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 id="dynamic-fade-demo" class="demo">
  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 id="animated-number-demo">
  <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 id="example-7">
  <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:style="{ backgroundColor: tweenedCSSColor }" class="example-7-color-preview" ></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 id="example-8">
  <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就可以辅助完成这几种状态之间的过渡动画,来制作你的欢迎页面、加载指示、以及更加带有情感的提示

目录
相关文章
|
23小时前
|
缓存 JavaScript
【vue】如何搭建拦截器和设置路由守卫(基于token认证)
【vue】如何搭建拦截器和设置路由守卫(基于token认证)
5 0
|
1天前
|
设计模式 JavaScript 前端开发
Vue源码学习需要哪些工具和技能
【4月更文挑战第20天】学习Vue源码需具备的工具与技能:VS Code或WebStorm作为代码编辑器,Node.js与npm管理依赖,Git操作仓库。基础包括JavaScript、ES6+语法、前端知识(HTML/CSS/浏览器原理)及Vue基础知识。进阶则需源码阅读理解能力,调试技巧,熟悉设计模式和架构思想。学习方法强调系统学习、实践与持续关注Vue最新动态。
17 8
|
1天前
|
JavaScript 前端开发 编译器
Vue 源码学习路线
【4月更文挑战第20天】探索Vue源码涉及响应式系统、虚拟DOM、模板编译等核心概念。先掌握Vue基础知识、JavaScript(ES6+)和前端工程化。从源码入口文件开始,研究响应式、虚拟DOM、模板编译、实例方法、全局API及生命周期。理解编译器和渲染器工作原理,实践编写Vue插件,参与开源项目,阅读相关文章教程,持续关注Vue最新动态。这是一个循序渐进、需要耐心和实践的过程。
8 1
|
2天前
|
JavaScript 前端开发
鼠标监视 | 拖拽方块 | Vue
鼠标监视 | 拖拽方块 | Vue
5 0
|
2天前
|
JavaScript
Vue控制是否禁用disabled属性
Vue控制是否禁用disabled属性
10 1
|
2天前
|
JavaScript 前端开发
Vue鼠标悬浮切换图片
Vue鼠标悬浮切换图片
11 0
|
2天前
|
JavaScript 前端开发 内存技术
Vue入门:构建你的第一个Vue应用程序
【4月更文挑战第22天】Vue.js 入门教程:安装 Node.js 和 npm,使用 Vue CLI (`npm install -g @vue/cli`) 创建项目,选择预设或自定义配置。在 `src/components/` 创建 `HelloWorld.vue` 组件,显示数据属性。在 `App.vue` 中引入并注册组件,启动开发服务器 (`npm run serve`) 预览。开始你的 Vue 之旅!
|
2天前
|
JavaScript 前端开发 UED
动画效果:给 Vue 应用添加过渡和动画
【4月更文挑战第22天】Vue 框架提供强大的过渡和动画功能,增强用户体验,创建流畅的用户界面。通过CSS动画、设置过渡属性和自定义过渡,开发者能实现多样化效果。同时,结合组件状态、关注性能并测试优化,确保在不同设备上运行良好,打造引人入胜的应用交互。
|
5天前
|
JavaScript
Ant design Vue 父子组件传递(代码案例--不懂的地方可以私信本博主)
Ant design Vue 父子组件传递(代码案例--不懂的地方可以私信本博主)
10 0
|
5天前
|
JavaScript 前端开发
ant design vue 配置菜单外部打开
ant design vue 配置菜单外部打开
12 0