Vue.js学习笔记(六)

Posted by Ivens on November 29, 2019

前言

1
2
3
vue.js:634 [Vue warn]: 
<transition> can only be used on a single element. 
Use <transition-group> for lists.

注意: transition 标签下只能放单个元素, 多了只会显示第一个.

正文

Vue 中 CSS 动画原理

通过在特定时间点对transition添加样式,完成渐变效果.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<style>
  /* 在动画的第一帧规定完全透明为 0 ,默认值为1 */
  .v-enter {
    opacity: 0;
  }

  /* 侦听不透明度的变化,如果有则在 2s 完成. 动画进入第二帧, v-enter 消失, opacity 变为默认值, 开始执行渐变效果  */
  .v-enter-active{
    transition: opacity 2s;
  }

  /* 规定在消失渐变第二帧非透明度为 0 */
  .v-leave-to {
    opacity: 0;
  }

  /* 当侦听到 opacity 发生变化, 动画随之改变 */
  .v-leave-active {
    transition: opacity 2s;
  }
</style>

<div id="root">
  <transition>
    <p v-if="show">Hello World</p>
  </transition>
  <button @click="handleBtn()">切换</button>
</div>  

使用 Animate.css 库制作动画

1.导入引用文件

1
  <link href="https://cdn.bootcss.com/animate.css/3.7.2/animate.css" rel="stylesheet">

2.将 transition 标签进行改动

1
2
3
4
5
6
<transition
 enter-active-class="animated zoomInLeft" 
 leave-active-class="animated hinge"
>
  <p v-if="show">Hello World</p>
</transition>

给首次显示的元素添加动画

使用appear属性:

1
2
3
4
5
6
<transition
 appear
 appear-active-class="animated zoomInLeft"
>
  <p>AAA</p>
</transition>

过渡Animate 结合

transition标签添加 animated 属性的地方添加过渡类名.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<style>
.v-enter, .v-leave-to{
  opacity: 0;
}
.v-enter-active, .v-leave-active {
  transition: opacity 3s;
}
</style>

<transition
 enter-active-class="animated shake v-enter-active" 
 leave-active-class="animated shake v-leave-active"
>
  <p v-if="show">Hello World</p>
</transition>

但是这样会带来一个问题, Animate.css 动画持续时间为 1s , 但是我们设定的过渡动画时间为 3s , 这回造成当 animate 动画已经结束时, 过渡动画还没执行完的情况.

我们可以再 transition 标签中添加 type 属性来规定依据哪种动画的时间来执行.

1
2
3
4
5
6
7
 <transition
 type="transition"
 enter-active-class="animated shake v-enter-active" 
 leave-active-class="animated shake v-leave-active"
>
  <p v-if="show">Hello World</p>
</transition>

或者使用 :duration 属性来自定义时长.

1
2
3
4
5
6
7
 <transition
 :duration="4000"
 enter-active-class="animated shake v-enter-active" 
 leave-active-class="animated shake v-leave-active"
>
  <p v-if="show">Hello World</p>
</transition>

直到 4000ms 结束, 元素的类名才会发生变化.

1
2
3
4
5
6
7
 <transition
 :duration="{enter: 5000, leave: 5000}"
 enter-active-class="animated shake v-enter-active" 
 leave-active-class="animated shake v-leave-active"
>
  <p v-if="show">Hello World</p>
</transition>

这样可以更详细地控制时长.

JS 动画与 velocity.js

通过 Vue 给出的钩子, 我们可以通过 JS 实现简单动画.

入场:

  1. before-enter
  2. enter
  3. after-enter

出场:

  1. before-leave
  2. leave
  3. after-leave

我们在 transition 标签绑定事件, 然后在 methods 中实现.

1
2
3
4
5
6
7
<transition
 @before-enter="handleBeforeEnter"
 @enter="handleEnter"
 @after-enter="handleAfterEnter" 
 >
   <p v-if="show">Hello World</p>
</transition>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 methods: {
  handleBeforeEnter (el) {
    console.log('handleBeforeEnter');
    el.style.color= "red";
  },
  handleEnter (el,done) {
    setTimeout(() => {
      el.style.color= 'green';
    }, 1000);

    setTimeout(() => {
      done();
    }, 2000);
  },
  handleAfterEnter (el) {
    el.style.color= '#000';
  }
}

velocity.js 是 JS 的一个动画库, 直接引用即可:

1
<script src="https://cdn.bootcss.com/velocity/2.0.5/velocity.js"></script>

使用方法与上面的 JS 动画一样, 只是在钩子方法中使用 Velocity 对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
methods: {
  handleBeforeEnter (el) {
    el.style.opacity = 0;
  },
  handleEnter (el,done) {
    Velocity(el,{
      opacity: 1
    },{
      duration: 1000,
      // 注意: 动画结束要有 complete 属性
      complete: done
    })
  },
  handleAfterEnter (el) {
    console.log('动画结束')
  }
}

多元素或多组件的过渡

多元素过渡

与普通过渡使用方法一样用 transition 标签进行包裹, 区别是:

  • 为每个元素设置一个 key 值, 放置 Vue 的元素复用
  • 可以添加 mode 来规定动画的种类, 如: out-inin-out

多组件过渡

与普通过渡用法一样,可以通过 v-ifv-else 判断哪个元素显示, 也可以用动态组件 :is + 三元表达式 来判断显示哪一个组件.

列表过渡

与普通列表渲染无异, 在外层使用 transition-group 包裹, 在 style 中规定过渡样式.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<style>
  .v-enter, .v-leave-to{
    opacity: 0;
  }
  .v-enter-active, .v-leave-active{
    transition: opacity 1s;
  }
</style>

<div id="root">
  <transition-group>
    <div v-for="(item, index) in listA" :key="index">
      {{item}}
    </div>
  </transition-group>
  <button @click="handleClick">添加</button>
  <button @click="handleDelete">删除</button>
</div>

<script>
  var vm = new Vue({
    el: '#root',
    data() {
      return {
        listA: []
      }
    },
    methods: {
      handleClick () {
        this.listA.push('hello world');
      },
      handleDelete () {
        this.listA.pop();
      }
    }
  })
</script>

对动画进行封装

使用 Vue.component 对动画进行封装.

1
2
3
4
5
6
Vue.component('fade',{
  props: ['judege'],
  template: `<transition>
              <slot v-if="judege"></slot>
            </transition>`
})

header 中的 style 保留, 或者可以使用 JS 动画, 参照上文在子组件 methods 中使用周期钩子即可.