Blog of CodeJELLOW’S ENGINEERING NOTES
← 返回文章

VUE3之Animation(二)

VUE3之Animation(二) animate.css gsap库 利用gsap实现数字渐变效果 transition-group 列表的交替动画

animate.css

安装:

TEXT
npm install animate.css -save

在文件中添加引用:

TEXT
import "animate.css";

第一种使用方法和普通的animation用法差不多,需要使用动画的元素要被<transition>包裹,并在style中通过动画的名字使用animate.css的样式:

TEXT
<template>
  <div class="app">
      <div>
        <button @click="isShow=!isShow">显示/隐藏</button>
      </div>
      <transition name="sk" mode="out-in" :appear="true">
        <h2 class="title" v-if="isShow">hello world</h2>
      </transition>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        isShow: true
      }
    },
  }
</script>

<style scoped>

  .title{
    display: inline-block;
  }

  .sk-enter-active{
    animation: rollIn 1s ease-in
  }
  
  .sk-leave-active{
    animation: rollOut 1s ease-in
  }
</style>

第二种用法是直接在transition标签中加入enter-active-class和leave-active-class属性,属性值为”animate__animated “+动画名称:

TEXT
      <transition enter-active-class="animate__animated animate__rotateIn" 
        leave-active-class="animate__animated animate__rotateOutDownLeft">
        <h2 class="title" v-if="isShow">hello world</h2>
      </transition>

此外还有一些属性例如enter-to-class、enter-from-class、leave-to-class、leave-from-class

gsap库

安装:

TEXT
npm install gsap -save

导入:

TEXT
import gsap from "gsap";

transition的生命周期回调:

TEXT
<template>
  <div class="app">
      <div>
        <button @click="isShow=!isShow">显示/隐藏</button>
      </div>
      <transition @before-enter="beforeEnter"
        @enter="enter"
        @after-enter="afterEnter"
        @before-leave="beforeLeave"
        @leave="leave"
        @after-leave="afterLeave">
        <h2 class="title" v-if="isShow">hello world</h2>
      </transition>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        isShow: true
      }
    },
    methods: {
      beforeEnter() {
        console.log("beforeEnter");
      },
      enter() {
        console.log("enter");
      },
      afterEnter() {
        console.log("afterEnter");
      },
      beforeLeave() {
        console.log("beforeLeave");
      },
      leave() {
        console.log("leave");
      },
      afterLeave() {
        console.log("afterLeave");
      },
    },
  }
</script>

这些生命周期钩子对应了css中的enter-to-class等类。

使用gsap,就是在这些回调的方法中使用gsap的方法。其中from是从一个自定义的状态到结束状态,to方法是从初始状态到一个自定义的状态:

TEXT
<template>
  <div class="app">
      <div>
        <button @click="isShow=!isShow">显示/隐藏</button>
      </div>
      <transition  @enter="enter"
        @leave="leave"
        :css="false">
        <h2 class="title" v-if="isShow">hello world</h2>
      </transition>
  </div>
</template>

<script>
import gsap from "gsap";
  export default {
    data() {
      return {
        isShow: true,
        distance: 200
      }
    },
    methods: {
      enter(el, done) {
        console.log("enter");
        gsap.from(el,{
          scale:0,
          x:this.distance,
          // 默认是0.5s
          duration:1,
          // 如果不写时,默认在动画开始时同步回调done
          onComplete: done
        })
      },
      leave(el,done) {
        console.log("leave");
        gsap.to(el,{
          scale:0,
          x:200,
          duration:1,
          onComplete:done
        })
      },
    },
  }
</script>

其中回调方法中第一个参数el是指回调产生的元素,同时也需要传入给gsap,第二个参数是动画完成时的回调,一般需要在gasp的onComplete属性中写出。

transition的:css属性设置为false,可以跳过css检测,提高性能。

使用gsap的一个特点是通过JavaScript实现的,比较灵活。

利用gsap实现数字渐变效果

TEXT
<template>
  <div class="app">
    <input type="number" step="100" v-model="counter">
    <h2>当前计数:{{showNumber.toFixed(0)}}</h2>
  </div>
</template>

<script>
import gsap from 'gsap';
  export default {
    data() {
      return {
        counter:0,
        showNumber:0
      }
    },
    watch:{
      counter(newValue){
        gsap.to(this,{
          duration:1,
          showNumber:newValue
        })
      }
    }
  }
</script>

对数字进行观察,当数字发生变化时使用gsap的to方法,将要显示的数字变化在一个时期内变化到目标数字。

transition-group

transition-group有以下特点:

默认情况下,它不会渲染一个元素的包裹器,但是你可以指定一个元素并以tag attribute进行渲染;

过渡模式不可用,因为我们不再相互切换特有的元素;

内部元素总是需要提供唯一的key attribute值;

CSS过渡的类将会应用在内部的元素中,而不是这个组/容器本身;

基本使用:对一个列表中删除或增加的数字增加动画

在transition-group标签中增加一个tag属性,那么其中的元素都会被包裹在这个tag指定的容器里面:

TEXT
<template>
    <div>
        <button @click="addNum">添加数字</button>
        <button @click="removeNum">删除数字</button>

        <transition-group tag="p" name="sk">
            <span v-for="item in numbers" :key="item" class="item">
                {{item}}
            </span>
        </transition-group>
    </div>
</template>

增加、删除数字的逻辑:

TEXT
<script>
    export default {
        data() {
            return {
                numbers:[1,2,3,4,5,6,7,8,9],
                numberCounter:10
            }
        },
        methods: {
            addNum(){
                this.numbers.splice(this.randomIndex(),0,this.numberCounter++);
            },
            removeNum(){
                this.numbers.splice(this.randomIndex(),1);
            },
            randomIndex(){
                return Math.floor(Math.random()*this.numbers.length);
            }
        },
    }
</script>

动画的实现还是使用的transition的类:

TEXT
<style scoped>
    .item{
        margin-right: 10px;
        display: inline-block;
    }

    .sk-enter-from,
    .sk-leave-to{
        opacity: 0;
        transform: translateY(30px);
    }

    .sk-enter-active,
    .sk-leave-active{
        transition: all 1s ease;
    }
</style>
图片暂不可用。

为队列中的其它数字增加动画效果:vue中已经帮助我们考虑到了这种情况,因此只需要使用transition的-move类就可以实现了:

TEXT
<style scoped>
    .item{
        margin-right: 10px;
        display: inline-block;
    }

    .sk-enter-from,
    .sk-leave-to{
        opacity: 0;
        transform: translateY(30px);
    }

    .sk-enter-active,
    .sk-leave-active{
        transition: all 1s ease;
    }

// 防止在删除过程中其它元素动画因为被占位了而不生效的问题
    .sk-leave-active{
        position: absolute;
    }

    .sk-move{
        transition: transform 1s ease;
    }
</style>
图片暂不可用。

列表的交替动画

TEXT
<template>
    <div>
        <input v-model="keyword">
        <transition-group tag="ul" name="sk" :css="false"
            @before-enter="beforeEnter"
            @enter="enter"
            @leave="leave">
            <li v-for="(item,index) in showNames" :key="item" :data-index="index">
                {{item}}
            </li>
        </transition-group>
    </div>
</template>

<script>
import gsap from 'gsap';
    export default {
        data() {
            return {
                names:["abc","cba","nba","sk","lilei","hmm","kobe"],
                keyword: ""
            }
        },
        computed:{
            showNames(){
                return this.names.filter(item=>item.indexOf(this.keyword)!==-1)
            }
        },
        methods: {
            beforeEnter(el){
                el.style.opacity=0;
                el.style.height=0;
            },
            enter(el,done){
                gsap.to(el,{
                    opacity:1,
                    height:"1.5em",
                    delay: el.dataset.index *0.2,
                    onComplete:done
                })
            },
            leave(el,done){
                gsap.to(el,{
                    opacity:0,
                    height:0,
                    delay: el.dataset.index *0.2,
                    onComplete:done
                })
            }
        },
    }
</script>

通过gsap的delay属性,实现根据下标完成延时显示的效果。

通过 RSS 订阅更新 →