《循序渐进Vue.js前端开发实战》电子书学习-第8章-动画

Vue中实现过渡动画的多种方法解析

合理使用动画可以极大提高用户的使用体验。vue中提供了一些和过渡和动画相关的抽象概念,可以帮助我们方便快速的定义和使用动画,本节从css动画开始学习,逐步深入vue中动画apl的应用

使用CSS3创建动画

c3本身支持丰富的动画效果,例如组件的过渡、渐变、移动、翻转等都是可以添加带个话效果。c3动画的核心是定义keyframes或transition。keyframes定义了动画的行为,比如对于颜色渐变的动画,需要定义起始的颜色和终止的颜色,浏览器会自动帮助我们计算期间的所有中间态来执行动画,transtition的使用更加简单,当组件的css属性变化,使用transition来定义其过渡动画属性

transition过渡动画

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="https://unpkg.com/vue@next"></script>
  <style>
    .demo{
      width: 100px;
      height: 100px;
      background-color: red;
    }
    .demo-ani{
      width: 200px;
      height: 200px;
      background-color: blue;
      transition: width 2s,height 2s,background-clor 2s;
    }
  </style>
</head>
<body>
  <div id="Application">
    <div :class="cls" @click="run"></div>
  </div>
  <script>
    const App=Vue.createApp({
      data() {
        return {
          cls:"demo"
        }
      },
      methods: {
        run(){
          if(this.cls=="demo"){
            this.cls="demo-ani"
          }else{
            this.cls="demo"
          }
        }
      },
    })
    App.mount("#Application")
  </script>
</body>
</html>

上面的代码里,css中定义的demo-ani类中指定了transition属性,这个属性可以设置要过渡的属性和动画事件。运行代码,点击色块,可以看到色块变大的过程中,会有动画效果,上面的代码简写了,我们也可以逐条属性进行设置

 .demo{
      width: 100px;
      height: 100px;
      background-color: red;
      transition-property: width,height,background-color;
      transition-duration: 1s;
      transition-timing-function: linear;
      transition-delay: 2s
    }

p的设置了动画的属性,du的由来设置动画的执行时长,tim-fun的是用来设置执行方式,liner表示线性执行,del表示延时多久执行动画

keyframes动画

transition动画适合用来创建简单的过渡效果,c3里面支持使用animation属性来配置更加复杂的动画效果。animation属性根据keyframes配置来执行关键帧的动画效果

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="https://unpkg.com/vue@next"></script>
  <style>
    @keyframes animation1{
      0%{
        background-color: red;
        width: 100px;
        height: 100px;
      }
      25%{
        background-color: orchid;
        width: 200px;
        height: 200px;
      }
      75%{
        background-color: green;
        width: 150px;
        height: 150px;
      }
      100%{
        background-color: blue;
        width: 200px;
        height: 200px;
      }
    }
    .demo{
      width: 100px;
      height: 100px;
      background-color: red;
    }
    .demo-ani{
      animation: animation1 4s linear;
      width: 200px;
      height: 200px;
      background-color: blue;
    }
  </style>
</head>
<body>
  <div id="Application">
    <div :class="cls" @click="run"></div>
  </div>
  <script>
    const App=Vue.createApp({
      data() {
        return {
          cls:"demo"
        }
      },
      methods: {
        run(){
          if(this.cls=="demo"){
            this.cls="demo-ani"
          }else{
            this.cls="demo"
          }
        }
      },
    })
    App.mount("#Application")
  </script>
</body>
</html>

带百分号的也就是一个关键帧,在其中可以定义元荤素的各种渲染属性,比如宽高、位置、颜色等,在定义keyframes的时候,如果只关心起始和终止状态,也没有不使用百分号,使用from和to

js实现动画效果

动画的本质是将元素的变化以渐变的方式来完成,把大的状态变化拆成非常多小的状态变化,通过不断执行这些变化来达成动画效果。使用js的定时器按照一定频率进行组件状态变化也可以实现动画效果

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="https://unpkg.com/vue@next"></script>
</head>
<body>
  <div id="Application">
    <div :style="{backgroundColor:'blue',width:width+'px',height:height+'px'}" @click="run"></div>
  </div>
  <script>
    const App=Vue.createApp({
      data() {
        return {
          width:100,
          height:100,
          timer:null
        }
      },
      methods: {
        run(){
          this.timer=setInterval(this.animation,10)
        },
        animation(){
          if(this.width==200){
            clearInterval(this.timer)
          }else{
            this.width++
            this.height++
          }
        }
      },
    })
    App.mount("#Application")
  </script>
</body>
</html>

setinterval方法是用来开启一个定时器的,代码设置了每十毫秒就执行一次回调函数,在回调函数里,逐步将色块的尺寸放大,就有了动画效果,使用JavaScript可以更加灵活的控制动画的效果,在实际开发,结合canvas的使用,js会有强大的自定义动画效果。动画结束后,需要将定时器停止

vue过渡动画

vue过度动画的核心原理是通过css类来实现的,vue帮助我们在组件的不同生命周期自动切换不同的css类

vue里默认提供了一个名为transition的内置组件,可以用来包装要展示过渡动画的组件。transition组件的name属性用来设置要执行的动画名称,vue约定一系列css类名规则来定义各个过渡过程里的组件状态

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="https://unpkg.com/vue@next"></script>
  <style>
    .ani-enter-from{
      width: 0px;
      height: 0px;
      background-color: red;
    }
    .ani-enter-active{
      transition: width 2s,height 2s,background-color 2s;
    }
    .ani-enter-to{
      width: 100px;
      height: 100px;
      background-color: blue;
    }
    .ani-leave-from{
      width: 100px;
      height: 100px;
      background-color: blue;
    }
    .ani-leave-active{
      transition: width 2s,height 2s,background-color 3s;
    }
    .ani-leave-to{
      width: 0px;
      height: 0px;
      background-color: red;
    }
  </style>
</head>
<body>
  <div id="Application">
    <button @click="click">显示/隐藏</button>
    <transition name="ani">
      <div v-if="show">

      </div>
    </transition>
  </div>
  <script>
    const App=Vue.createApp({
      data() {
        return {
          show:false
        }
      },
      methods: {
        click(){
          this.show=!this.show
        }
      },
    })
    App.mount("#Application")
  </script>
</body>
</html>

点击功能按键,组件在显示和隐藏的时候会要特殊的过渡动画效果。代码的核心是定义的六个特殊的css类,这六个css类没有显示使用,但是在组件执行动画里起到了不可替代的作用。当我们为transition组件的name属性设置动画名称后,当组件被插入页面被移除的时候,会自动寻找动画名称开头的css类,也就是上面定义的六个css类

也就是x-enter/leave-from/active/to

x指的是定义的过渡动画的名称。六种css类,前三种用来定义组件被插入页面的动画效果,后面三种用来定义组件被移除页面的动画效果

x-e-f类在组件即将被插入页面的时候被添加在组件和是哪个,可以理解为组件的初始状态,元素被插入页面后此类会马上被移除

x-e-t类在组件被插入页面后立即被添加,此时x-e-f类会被移除,可以理解为组件过渡的最终状态

x-e-a类在组件的整个插入过渡动画都被会添加,直到组件的过渡动画结束后才会被移除。可以在这个类里面定义组件过渡动画的时长、方式、延迟

x-e-f和第一个相反,在组件即将被移除的时候此类会被添加,用来定义移除组件时过渡动画的起始状态

x-l-t则是对于移除组件动画的终止状态

x-l-a类在组件移除过渡的整个过程都会被添加,直到组件过渡动画结束后才会被移除。

上面六种css类虽然被添加的时机不同,但是最终都会被移除,因此当动画执行完成后,组件的样式并不会保留,跟常见的是在组件本身绑定一个最终状态的样式类

<transition name="ani">
      <div v-if="show" class="demo">

      </div>
    </transition>

css代码

 .demo{
      width: 100px;
      height: 100px;
      background-color: blue;
    }

设置动画过程中的监听回调

对于组件的加载或卸载过程,有一系列的生命周期函数会被调用,对于vue中的转场动画,也可以注册一系列的动画函数来对其过程进行监听

例如

 <div id="Application">
    <button @click="click">显示/隐藏</button>
    <transition name="ani"
    @before-enter="beforeEnter"
    @enter="enter"
    @after-enter="afterEnter"
    @enter-cancelled="enterCancelled"
    @before-leave="beforeLeave"
    @leave="leave"
    @after-leave="afterLeave"
    @leave-cancelled="leaveCancelled"
    >
      <div v-if="show" class="demo">
        
      </div>
    </transition>

注册的回调方法需要在组件的methods选项里实现

 

 methods: {
        click(){
          this.show=!this.show
        },
        beforeEnter(el){
          console.log("beforeEnter");
        },
        enter(el,done){
          console.log("enter");
        },
        afterEnter(el){
          console.log("afterEnter");
        },
        enterCancelled(el){
          console.log("enterCancelled");
        },
        beforeLeave(el){
          console.log("beforeLeave");
        },
        leave(el,done){
          console.log("leave");
        },
        afterLeave(el){
          console.log("afterleave");
        },
        leaveCancelled(el){
          console.log("leaveCancelled");
        }
      },

借助回调函数,我们在组件过渡动画过程里实现复杂的业务逻辑可以通过js来自定义过度动画,当需要自定义过渡动画的时候,需要将transition组件的css属性关掉

上面的回调函数里的enter和leave除了会将当前元素与作为参数,还有一个函数类型的done参数,如果将css属性关闭,决定用js来实现自定义的过度动画,那么done函数就需要被手动调用,要不然动画会立即完成

多个组件的过渡动画

vue的transition组件支持同时包赚更多个互斥的子组件元素,从而实现多组件的过渡效果,在实际开发,有很多类似情况,例如a消失的同时b展示,例子:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="https://unpkg.com/vue@next"></script>
  <style>
    .demo{
      width: 100px;
      height: 100px;
      background-color: blue;
    }
    .demo2{
      width: 100px;
      height: 100px;
      background-color: blue;
    }
    .ani-enter-from{
      width: 0px;
      height: 0px;
      background-color: red;
    }
    .ani-enter-active{
      transition: width 3s,height 3s background-color 3s;
    }
    .ani-enter-to{
      width: 100px;
      height: 100px;
      background-color: blue;
    }
    .ani-leave-from{
      width: 100px;
      height: 100px;
      background-color: blue;
    }
    .ani-leave-active{
      transition: width 3s,height 3s,background-color 3s;
    }
    .ani-leave-to{
      width: 0px;
      height: 0px;
      background-color: red;
    }
  </style>
</head>
<body>
  <div id="Application">
    <button @click="click">显示/隐藏</button>
    <transition name="ani">
    <div v-if="show" class="demo"></div>
    <div v-else class="demo2"></div>
    </transition>
  </div>
  <script>
    const App=Vue.createApp({
      data() {
        return {
          show:false
        }
      },
      methods: {
        click(){
          this.show=!this.show
        }
      },
    })
    App.mount("#Application")
  </script>
</body>
</html>

运行代码,点击按钮,可以看到两个色块以过渡动画的形式交替出现。默认情况两个元素的插入和移除动画会同步进行,大多数需要移除动画执行完成后,再执行插入动画。要实现此功能有对transition组件的mode属性进行设置,当我们设置为out-in,就会先执行移除动画,再执行插入动画,设置为in-out就先执行插入动画,再执行移除,如下

<transition name="ani" mode="in-out">
    <div v-if="show" class="demo"></div>
    <div v-else class="demo2"></div>
    </transition>

列表过渡动画

实际开发里,列表是一种非常流行的页面设计的方式。vue里,通常使用v-for指令来动态构建列表视图,在动态构建列表视图的过程中,其中的元素经常有增删、重拍等操作,在vue里使用transition-group组件可以非常方便的实现列表元素变动的动画效果

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="https://unpkg.com/vue@next"></script>
  <style>
    .list-enter-active,
    .list-leave-active{
      transition: all 1s ease;
    }
    .list-enter-from,
    .list-leave-to{
      opacity: 0;
    }
  </style>
</head>
<body>
  <div id="Application">
    <button @click="click">添加元素</button>
    <transition-group name="list">
    <div v-for="item in items" :key="item">
      元素:{{item}}
    </div>
   
    </transition-group>
  </div>
  <script>
    const App=Vue.createApp({
      data() {
        return {
          items:[1,2,3,4,5]
        }
      },
      methods: {
        click(){
          this.items.push(this.items[this.items.length-1]+1)
        }
      },
    })
    App.mount("#Application")
  </script>
</body>
</html>

单击添加元素,可以实现渐进式插入

 在使用transition-group组件实现列表动画时,和transition类似,首先需要定义动画所需的css类。如果使用列表动画,列表的每一个元素都需要有一个唯一的key值。

除了对列表元素进行增删,排序过程也可以采用动画进行过渡,只需要额外定义一个v-move;类的特殊动画类就行

优化用户列表页面

对于前端网页开发,功能实现仅仅是开发产品的第一步,如何给用户以最优的使用体验才是工程师的核心关注点,尝试给第七章的用户列表实例加入一些动画效果

  template:`
      <div class="container">
      <div class="content">
        <input type="radio" :value="-1" v-model="sexFilter">全部
        <input type="radio" :value="0" v-model="sexFilter">男
        <input type="radio" :value="-1" v-model="sexFilter">女
      </div>
      <div class="content">搜索:<input type="text" v-model="searchKey"></div>
      <div class="content">
        
        <div class="tab" width="300px">
          <div>
            <div class="item">姓名</div>
            <div class="item">性别</div>
          </div>
          <transition-group name="list">
            <div v-for="(data,index) in showDatas" :key="data.name">
            <div class="item">{{data.name}}</div>
            <div class="item">{{data.sex=='0' ? '男':'女'}}</div>
            </div>
          </transition-group>
        </div>
      </div>
    </div>
      `

css样式和动画效果

<style>
    .container{
      margin: 50px;
    }
    .content{
      margin: 20px;
    }
    .tab{
      width: 300px;
      position: absolute;
    }
    .item{
      border: gray 1px solid;
      width: 148px;
      text-align: center;
      transition: all 0.8s ease;
      display: inline-block;
    }
    .list-enter-active{
      transition: all 1s ease;
    }
    .list-enter-from,
    .list-leave-to{
      opacity: 0;
    }
    .list-move{
      transition: transform 1s ease;
    }
    .list-leave-active{
      position: absolute;
      transition: all 1s ease;
    }
  </style>

过渡效果灰常不错

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值