13Vue-动画实现

115 阅读1分钟

认识动画

图片.png

App.vue

<template>
    <div>
    //对单个元素,直接用transition进行包裹
    //写上name就可以在style写动画了
        <transition name="why">
            <h2 v-if="isShow">Hello</h2>
        </transition>
    </div>
</template>

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

<style scoped>
进来的时候透明度为0,出去的时候透明度为1
    .why-enter-from,
    .why-leave-to{
    透明度
        opacity:0;  透明
    }
    
    .why-enter-to,
    .why-leave-from{
        opacity:1;  显示
    }
    
    .why-enter-active,
    .why-leave-active{
对opacity进行过度,2秒,
        transition:opacity 2s ease;
    }
</style>

图片.png

图片.png

图片.png

图片.png

css过渡动画

App.vue

<template>
    <div>
    //对单个元素,直接用transition进行包裹
    //写上name就可以在style写动画了
        <transition name="why">
            <h2 v-if="isShow">Hello</h2>
        </transition>
    </div>
</template>

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

<style scoped>
    .why-enter-active,{
    动画,1s,动画执行曲线
        animation:bounce 1s ease
    }
    .why-leave-active,{
    动画,1s,动画执行曲线,动画翻转,离开和bounce相反的时候
        animation:bounce 1s ease reverse
    }
    
//帧动画    
    @keyframes bounce{
       0%{
           transform:scale(0)  缩放程度是0
       }
       
       50%{
           transform:scale(1.2)
       }
       
       100%{
           transform:scale(1)
       }
    }
</style>

同时设置过度和动画(transition和animation)

既有大小缩放变化,又有透明度变化

<template>
    <div>
    //对单个元素,直接用transition进行包裹
    //写上name就可以在style写动画了
//根据transition来决定动画时间结束    
        <transition name="why" type="transition">
            <h2 v-if="isShow">Hello</h2>
        </transition>
    </div>
</template>

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

<style scoped>
    .why-enter-from,
    .why-leave-to{
    透明度
        opacity:0;  透明
    }
    
    .why-enter-active,
    .why-leave-active{
        transition:opacity 1s ease;
    }

    .why-enter-active,{
    动画,1s,动画执行曲线
        animation:bounce 1s ease;
    }
    .why-leave-active,{
    动画,1s,动画执行曲线,动画翻转,离开和bounce相反的时候
        animation:bounce 1s ease reverse;
    }
    
//帧动画    
    @keyframes bounce{
       0%{
           transform:scale(0)  缩放程度是0
       }
       
       50%{
           transform:scale(1.2)
       }
       
       100%{
           transform:scale(1)
       }
    }
</style>

图片.png

显示的指定动画时间

<transition 
name="why" 
type="transition" 
:duration="1000">

:duration用来设置指定时间,这个时候style里设置的时间就失效了

也可以指定某个动作的时间

图片.png

过度的模式mode

图片.png

<template>
    <div> 
    mode="in-out"等到我进入动画结束后,才开始离开动画
    out-in:相反
        <transition name="why" mode="in-out">
            <h2 v-if="isShow">Hello</h2>
        </transition>
    </div>
</template>
<component>动态组件切换

appear 表示 一打开页面,就展示动画效果
图片.png

结合三方库

图片.png

npm install animate.css
<template>
    <div>
    //对单个元素,直接用transition进行包裹
    //写上name就可以在style写动画了
//根据transition来决定动画时间结束    
        <transition
        enter-active-class="animate__animated animate__fadeIndown
        
        "
        >
            <h2 v-if="isShow">Hello</h2>
        </transition>
    </div>
</template>

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

<style scoped>
    .why-enter-active{
        animation:bounceInUp 1s ease-in;
    }
    .why-leave-active{
    //使用库提供的
        animation:bounceInUp 1s ease-in reverse;
    }
</style>

图片.png

gsap库

图片.png

图片.png

npm install gsap

图片.png

<transition @before-enter="beforeEnter"
            @enter="enter"
            @after-enter="afterEnter"
            @before-leave="beforeLeave"
            @leave="leave"
            @afterLeave="afterLeave"
            :css="false" 跳过css的检测
            >
<h2></h2>            
methods:{
    beforeEnter(){}
    指:从某一个地方,达到某一个状态
    enter(element,done){
        gsap.from(element,{
            缩放scale:0,
                x:200  等价于=> translate=200
                
            当我们动画执行完后,会执行这个回调下一个函数
                onComplete:done 
        })
    }
    afterEnter(){}
    beforeLeave(){}
    leave(el,done){
        gsap.to(el,{
            scale:0,
            x:200
            onComplete:done
        })
    }
    afterLeave(){}
}            

gsap实现数字变化

图片.png

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

<script>
  import gsap from 'gsap';

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

<style scoped>
</style>

列表的过渡

图片.png

图片.png

App.vue

<template>
    <div>
        <button @click="addNum"></button>
        <button @click="removeNum"></button>
        <transition-group tag="p" name="why">
            <span v-for="item in numbers" :key="item">
                {{item}}
            </span>
        </transition-group>
    </div>
</template>

<script>
    import 
    export default{
        components:{
            
        }
        data(){
            return{
                numbers:[0,1,2,3,4,5,6,7,8,9]
                numCounter:10
            }
        },
        methods:{
            addNum(){
            //随机添加到某一位置
            //1:位置,2:删除几个,3:添加的
                this.numbers.splice(
                    this.randomIndex(),
                    0,
                    this.numCounter++)
            },
            removeNum(){
             this.numbers.splice(this.randomIndex(),1)
            },
            randomIndex(){
                return             
                Math.floor(
                Math.random()*this.numbers.length)
            }
        }
        
        
    }
</script>

<style>
    .item{
        margin-right:10px;
//span标签是行内的,所以添加Y动画会限制,需要改为inline-block        
        display:inline-block;
    }
    .why-enter-from,
    .why-leave-to{
        opacity:0;
        transform:translateY(30px;)从Y=30的坐标来
    },
    //因为enter-leave和leave-from的透明效果是1,所以不用写了
    
    .why-enter.active,
    .why-leave.active{
        transition:all 1s ease;
    }
</style>

列表过渡的移动动画

图片.png

npm install lodash

App.vue

<template>
    <div>
        <button @click="addNum">添加数字</button>
        <button @click="removeNum">删除数字</button>
        <button @click="shuffleNum">数字洗牌</button>
        
        <transition-group tag="p" name="why">
            <span v-for="item in numbers" :key="item">
                {{item}}
            </span>
        </transition-group>
    </div>
</template>

<script>
    import 
    export default{
        components:{
            
        }
        data(){
            return{
                numbers:[0,1,2,3,4,5,6,7,8,9]
                numCounter:10
            }
        },
        methods:{
            addNum(){
            //随机添加到某一位置
            //1:位置,2:删除几个,3:添加的
                this.numbers.splice(
                    this.randomIndex(),
                    0,
                    this.numCounter++)
            },
            removeNum(){
             this.numbers.splice(this.randomIndex(),1)
            },
            randomIndex(){
                return             
                Math.floor(
                Math.random()*this.numbers.length)
            },
            shuffleNum(){
            //数字洗牌,然后生成新数组
                this.numbers = _.shuffle(this.numbers)
            }
        }
        
        
    }
</script>

<style>
    .item{
        margin-right:10px;
//span标签是行内的,所以添加Y动画会限制,需要改为inline-block        
        display:inline-block;
    }
    .why-enter-from,
    .why-leave-to{
        opacity:0;
        transform:translateY(30px;)从Y=30的坐标来
    },
    //因为enter-leave和leave-from的透明效果是1,所以不用写了
    
    .why-enter.active,
    .why-leave.active{
        transition:all 1s ease;
    }
    
    .why-leave.active{
移除的时候,其实还在占着位置,其他数字想要移动的时候会卡住   
        position:absolute 脱离标准流
    }
    
    .why-move{
    位移动画
        transition:transform;
    }
</style>

列表的交错过渡案例

<template>
  <div>
    <input v-model="keyword">
    <transition-group tag="ul" name="why" :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", "why", "lilei", "hmm", "kobe", "james"],
        keyword: ""
      }
    },
    computed: {
      showNames() {
//item为true才会保留在数组中,false的筛选掉      
        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.5,
          onComplete: done
        })
      },
      leave(el, done) {
        gsap.to(el, {
          opacity: 0,
          height: 0,
          delay: el.dataset.index * 0.5,
          onComplete: done
        })
      }
    }
  }
</script>

<style scoped>
  /* .why-enter-from,
  .why-leave-to {
    opacity: 0;
  }

  .why-enter-active,
  .why-leave-active {
    transition: opacity 1s ease;
  } */
</style>