一、使用 Vue 实现基础的 CSS 过渡与动画效果

  1. 数据控制css交互

    • css中书写样式;
    • data中书写样式;
      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
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      <!DOCTYPE html>
      <html lang="en">
      <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>基础的 CSS 过渡与动画效果</title>
      <script src="https://unpkg.com/vue@next"></script>
      <style>
      /* 动画 */
      @keyframes leftToRight {
      0% {
      transform: translate(-100px);
      }
      50% {
      transform: translate(-50px);
      }
      0% {
      transform: translate(0px);
      }
      }
      .animation {
      animation: leftToRight 3s;
      }

      /* 过度 */
      .transition {
      transition: 3s background-color ease;
      }
      .red {
      background-color: red;
      }
      .yellow {
      background-color: yellow;
      }

      .transition1 {
      transition: 3s background-color ease;
      }
      </style>
      </head>
      <body>
      <div id="root">
      </div>
      <script>
      const app = Vue.createApp({
      data() {
      return {
      animate: {
      transition: true,
      animation: true,
      red: true,
      yellow: false
      },
      animate1: {
      transition1: true,
      },
      styleObj: {
      background: "pink"
      }
      }
      },
      methods: {
      handleClick() {
      this.animate.animation = !this.animate.animation;
      this.animate.red = !this.animate.red;
      this.animate.yellow = !this.animate.yellow;
      this.styleObj.background === "pink" ? this.styleObj.background = "blue" : this.styleObj.background = "pink";
      }
      },
      template: `
      <div>
      <div :class="animate">hello word!</div>
      <div :class="animate1" :style="styleObj">hello word!</div>
      <button @click="handleClick">切换</button>
      </div>
      `
      });

      app.mount("#root");
      </script>
      </body>
      </html>

      二、使用 transition 标签实现单元素组件的过渡和动画效果(1)

  2. <transition>....</transition>

    • 配合在style中书写:入场动画
      • .v-enter-from
        • 开始状态
      • .v-enter-active
        • 过渡动画
      • .v-enter-to
        • 结束状态
    • 配合在style中书写:出场动画
      • .v-leave-from
        • 开始状态
      • .v-leave-active
        • 过渡动画
      • .v-leave-to
        • 结束状态
  3. <transition name="seconde">....</transition>

    • 配合在style中书写:入场动画
      • .seconde-enter-active
        • 入场动画
      • .seconde-leave-active
        • 出场动画
          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
          38
          39
          40
          41
          42
          43
          44
          45
          46
          47
          48
          49
          50
          51
          52
          53
          54
          55
          56
          57
          58
          59
          60
          61
          62
          63
          64
          65
          66
          67
          68
          69
          70
          71
          72
          73
          74
          75
          76
          77
          78
          79
          80
          81
          82
          83
          <!DOCTYPE html>
          <html lang="en">
          <head>
          <meta charset="UTF-8">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <title>transition标签的使用</title>
          <script src="https://unpkg.com/vue@next"></script>
          <style>
          /* 过渡 */
          .v-enter-from {
          opacity: 0;
          }
          .v-enter-active, .v-leave-active {
          transition: opacity 3s ease-in;
          }
          .v-enter-to {
          opacity: 1;
          }
          /*可以省略 .v-leave-from {
          opacity: 1;
          } */
          /*可以合并 .v-leave-active {
          transition: opacity 3s ease-out;
          } */
          .v-leave-to {
          opacity: 0;
          }

          /* 动画 */
          @keyframes shake {
          0% {
          transform: translateX(100px);
          }
          50% {
          transform: translateX(50px);
          }
          100% {
          transform: translateX(0px);
          }
          }
          .seconde-enter-active {
          animation: shake 3s;
          }
          .seconde-leave-active {
          animation: shake 3s;
          }
          </style>
          </head>
          <body>
          <div id="root">
          </div>
          <script>
          const app = Vue.createApp({
          data() {
          return {
          show: false
          }
          },
          methods: {
          handleClick() {
          this.show = !this.show;
          }
          },
          template: `
          <div>
          <transition>
          <div v-if="show">hello word!</div>
          </transition>
          <button @click="handleClick">切换</button>
          </div>
          <div>
          <transition name="seconde">
          <div v-if="show">hello word!</div>
          </transition>
          <button @click="handleClick">切换</button>
          </div>
          `
          });

          app.mount("#root");
          </script>
          </body>
          </html>

          三、使用 transition 标签实现单元素组件的过渡和动画效果(2)

  4. 若使用<transition enter-active-class="enter" leave-active-class="leave" >...</transition>自定义class名的语法

    • 在style中可使用该属性自动定义的class名
  5. 使用 https://animate.style/ 动画库

    • 引入动画库
      1
      2
      3
      4
      5
      6
      <head>
      <link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"
      />
      </head>
    • 自定义class名可以直接调用动画库的class生成动画
      1
      <h1 class="animate__animated animate__bounce">An animated element</h1>
      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
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      <!DOCTYPE html>
      <html lang="en">
      <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>transition标签的使用</title>
      <script src="https://unpkg.com/vue@next"></script>
      <link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"
      />
      <style>
      /* 过渡 */
      .v-enter-from {
      opacity: 0;
      }
      .enter, .leave {
      transition: opacity 3s ease-in;
      }
      .v-enter-to {
      opacity: 1;
      }
      /*可以省略 .v-leave-from {
      opacity: 1;
      } */
      /*可以合并 .v-leave-active {
      transition: opacity 3s ease-out;
      } */
      .v-leave-to {
      opacity: 0;
      }

      </style>
      </head>
      <body>
      <div id="root">
      </div>
      <script>
      const app = Vue.createApp({
      data() {
      return {
      show: false
      }
      },
      methods: {
      handleClick() {
      this.show = !this.show;
      }
      },
      template: `
      <div>
      <transition
      enter-active-class="enter"
      leave-active-class="leave"
      >
      <div v-show="show">hello word!</div>
      </transition>
      <button @click="handleClick">切换</button>
      </div>
      <div>
      <transition
      enter-active-class="animate__animated animate__bounce"
      leave-active-class="animate__animated animate__flipInY"
      >
      <div v-show="show">hello word!</div>
      </transition>
      <button @click="handleClick">切换</button>
      </div>
      `
      });

      app.mount("#root");
      </script>
      </body>
      </html>

      四、使用 transition 标签实现单元素组件的过渡和动画效果(3)

  6. 过渡 + 动画同时使用时,对过程时间长短的控制方法

    1. <transition type="animation/transition">...</transition>:
      • 同时使用动画和过渡时,使用type确定以其中一个的结束时间为准;
    2. <transition :duration="1000">...</transition>:
      • 行内可以固定动画或过渡的开始到结束时间,毫秒为单位;
  7. <transition :css="false">...</transition>:

    • 标签行内去除css控制效果的方法;
  8. transition标签中使用钩子控制动画

    • 当只用 JavaScript 过渡的时候,在 enter 和 leave 中必须使用 done 进行回调。否则,它们将被同步调用,过渡会立即完成。
    • 推荐对于仅使用 JavaScript 过渡的元素添加 v-bind:css=”false”,Vue 会跳过 CSS 的检测。这也可以避免过渡过程中 CSS 的影响。
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      <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>

      五、组件和元素切换动画的实现

  9. appear 设置节点在初始渲染的过渡

    • 无论是 appear attribute 还是 v-on:appear 钩子都会生成初始渲染过渡。
      1
      2
      3
      <transition appear>
      <!-- ... -->
      </transition>
  10. 过渡模式

    • 在“on”按钮和“off”按钮的过渡中,两个按钮都被重绘了,一个离开过渡的时候另一个开始进入过渡。这是 的默认行为 - 进入和离开同时发生。
    • 同时生效的进入和离开的过渡不能满足所有要求,所以 Vue 提供了过渡模式
      • in-out:新元素先进行过渡,完成之后当前元素过渡离开。
      • out-in:当前元素先进行过渡,完成之后新元素过渡进入。
        1
        2
        3
        <transition name="fade" mode="out-in">
        <!-- ... the buttons ... -->
        </transition>
  11. 多个单元素标签之间的切换过渡

    • 当有相同标签名的元素切换时,需要通过 key attribute 设置唯一的值来标记以让 Vue 区分它们,否则 Vue 为了效率只会替换相同标签内部的内容。即使在技术上没有必要,给在 组件中的多个元素设置 key 是一个更好的实践。
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      <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>
      可重写为:
      1
      2
      3
      4
      5
      <transition>
      <button v-bind:key="docState">
      {{ buttonMessage }}
      </button>
      </transition>
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      // ...
      computed: {
      buttonMessage: function () {
      switch (this.docState) {
      case 'saved': return 'Edit'
      case 'edited': return 'Save'
      case 'editing': return 'Cancel'
      }
      }
      }
  12. 多个单组件之间的切换过渡

    • 多个组件的过渡简单很多 - 我们不需要使用 key attribute。相反,我们只需要使用动态组件:
    1
    2
    3
    <transition name="component-fade" mode="out-in">
    <component v-bind:is="view"></component>
    </transition>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    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>'
    }
    }
    })
    1
    2
    3
    4
    5
    6
    7
    .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;
    }

    六、列表动画

  13. 使用 组件,列表的进入/离开过渡

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <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>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    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)
    },
    }
    })
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    .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);
    }

    2、使用 组件,列表的排序过渡

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.14.1/lodash.min.js"></script>
    <div id="list-complete-demo" class="demo">
    <button v-on:click="shuffle">Shuffle</button>
    <button v-on:click="add">Add</button>
    <button v-on:click="remove">Remove</button>
    <transition-group name="list-complete" tag="p">
    <span
    v-for="item in items"
    v-bind:key="item"
    class="list-complete-item"
    >
    {{ item }}
    </span>
    </transition-group>
    </div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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)
}
}
})
1
2
3
4
5
6
7
8
9
10
11
12
13
.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;
}

七、状态动画

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
38
39
40
41
42
43
44
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>状态动画</title>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="root">
</div>
<script>
const app = Vue.createApp({
data() {
return {
number: 1,
animateNumber: 0
}
},
methods: {
handleClick() {
this.number = 10;
if(this.animateNumber < 10) {
let animation = setInterval(() => {
this.animateNumber += 1;
if(this.animateNumber === 10) {
clearInterval(animation);
}
}, 1000)
}
}
},
template: `
<div>
<div>{{animateNumber}}</div>
<button @click="handleClick">增加</button>
</div>
`
});

app.mount("#root");
</script>
</body>
</html>