Administrator
发布于 2020-07-24 / 8218 阅读 / 0 评论 / 0 点赞

vue过渡动画

Vue中不同的组件如果进行不同的动画效果

在以前进行vue开发的时候,我们经常会使用<transition>组件进行动画的切换,在使用这个组件组件的时候,遇到过一个问题,就是如果动态赋值的组件进行不同的动画效果

针对上面的问题,我做了如下的测试

  • 首先,我使用了animate.css来进行动画效果,当然,大家也可以使用自己定义的动画
  • 其实,在每个要定义动画的组件里面,添加<transition>

话不多说,看代码

<template>
  <transition enter-active-class=" animated fadeInLeftBig" leave-active-class=" animated fadeOutLeftBig">
    <div class="movieList">
      <movie-item></movie-item>
      <movie-item></movie-item>
      <movie-item></movie-item>
    </div> 
  </transition>
 
</template>

<script>
import movieItem from "@/components/movieItem.vue";
export default {
  name:"movieList",
  data(){
    return {

    }
  },
  components:{
    movieItem
  }
}
</script>

<style lang="scss" scoped>
.movieList{
  position: absolute;
  left: 0px;
  top: 0px;
  width: 100%;
}
</style>

说明:上面的代码里面,我指定了enter-active-class与levae-active-class来设置进入与离开的动画

接下来,我们再来看一下另一个组件

<template>
  <transition enter-active-class=" animated fadeInRightBig" leave-active-class=" animated fadeOutRightBig">
    <div class="cinemalList">
      <movie-item></movie-item>
      <movie-item></movie-item>
      <movie-item></movie-item>
    </div> 
  </transition>
 
</template>

<script>
import movieItem from "@/components/movieItem.vue";
export default {
  name:"cinemalList",
  data(){
    return {

    }
  },
  components:{
    movieItem
  }
}
</script>

<style lang="scss" scoped>
.cinemalList{
  position: absolute;
  left: 0px;
  top: 0px;
  width: 100%;
}
</style>

大家可能已经发现了,我这里的动画效果和上面的动画效果上反向的,没错,我要的就是这效果

接下来,引入这两个组件

<template>
  <div class="index">
    <header class="header">
      猫眼电影
    </header>
    <ul class="topNav">
      <li :class="{active:pageType==0}" @click="pageType=0"><a href="#">影片</a></li>
      <li :class="{active:pageType==1}" @click="pageType=1"><a href="#">影院</a></li>
    </ul>
    <div class="content">
      <movie-list v-show="pageType==0"></movie-list>
      <cinemal-list v-show="pageType==1"></cinemal-list>
    </div>
  </div>
</template>

<script>
import movieList from "@/components/movieList.vue";
import cinemalList from "@/components/cinemalList.vue";
export default {
  name:"index",
  data(){
    return{
      pageType:0
    }
  },
  components:{
    movieList,cinemalList
  }
}
</script>

<style lang="scss" scoped>
@import "../scss/common.scss";
.index{
  position: absolute;
  width: 100%;
  height: 100%;
  left: 0px;
  top: 0px;
  .header{
    height: $headerHeight;
    @include flexbox(){
      justify-content: center;
      align-items: center;
    }
    font-size: 18px;
    background-color: $primaryColor;
    color: white;
  }
  .topNav{
    @include flexbox(){
      justify-content: center;
      align-items: center;
    };
    li{
      width: 50%;
      height: 40px;
      border-bottom: 3px solid lightgray;
      >a{
        text-decoration: none;
        color: black;
        display: block;
        width: 100%;
        height: 100%;
        @include flexbox(){
          justify-content: center;
          align-items: center;
        }
        
      }
      &.active{
          >a{
            color: $primaryColor;
          }
          border-bottom-color: $primaryColor;
      }
    }
  }
  .content{
      position: relative;
  }

}
</style>

说明 :上肌的content区域内部,我们引入了这两个组件,当这两个组件隐藏与显示的时候,我们就可以通过transition来实现animate.css的动画过渡效果了

使用路由的方式切换

上面的动态组件也可以通过路由来进行切换

import Vue from 'vue'
import Router from 'vue-router';
import index from '@/pages/index';
import movieList from '@/components/movieList';
import cinemalList from '@/components/cinemalList';

Vue.use(Router)

export default new Router({
    routes: [{
        path: '/',
        name: 'index',
        component: index,
        children: [{
                path: "movieList",
                name: "movieList",
                component: movieList
            },
            {
                path: "cinemalList",
                name: "cinemalList",
                component: cinemalList
            }
        ]
    }]
})

说明:上面的路由配置文件


<template>
  <div class="index">
    <header class="header">
      猫眼电影
    </header>
    <ul class="topNav">
        <router-link :to="{name:'movieList'}" active-class="active" tag="li"><a href="#">影片</a></router-link>
        <router-link :to="{name:'cinemalList'}" active-class="active" tag="li"><a href="#">影院</a></router-link>
    </ul>
    <div class="content">
      <keep-alive>
        <router-view></router-view>
      </keep-alive>
    </div>
  </div>
</template>

<script>
export default {
  name:"index",
  data(){
    return{
      pageType:0
    }
  }
}
</script>

<style lang="scss" scoped>
@import "../scss/common.scss";
.index{
  position: absolute;
  width: 100%;
  height: 100%;
  left: 0px;
  top: 0px;
  .header{
    height: $headerHeight;
    @include flexbox(){
      justify-content: center;
      align-items: center;
    }
    font-size: 18px;
    background-color: $primaryColor;
    color: white;
  }
  .topNav{
    @include flexbox(){
      justify-content: center;
      align-items: center;
    };
    li{
      width: 50%;
      height: 40px;
      border-bottom: 3px solid lightgray;
      >a{
        text-decoration: none;
        color: black;
        display: block;
        width: 100%;
        height: 100%;
        @include flexbox(){
          justify-content: center;
          align-items: center;
        }
        
      }
      &.active{
          >a{
            color: $primaryColor;
          }
          border-bottom-color: $primaryColor;
      }
    }
  }
  .content{
      position: relative;
  }

}
</style>

说明:上面是index.vue的文件代码,请注意看<router-link>的配置

Vue中使用JS动画库

::: tip
在一个动画的执行周期中,Vue提供了不同的钩子函数来让我们可以自定义自己的js动画,当然也可以使用第三方js动画。在纯粹使用js动画时,可以使用:css="false"来避免Vue的CSS监测。
:::

::: tip
在钩子函数enter(el,done)和leave(el,done)中的done方法必须进行回调,否则将被同步执行,过渡会立即完成。
:::

<transition
  @before-enter="handelBeforeEnter"
  @enter="handleEnter"
  @after-enter="handleAfterEnter"

  @before-leave="handleBeforeLeave"
  @leave="handleLeave"
  @after-leave="handleAfterLeave"
>
  <p v-if="isShow">Hello, world</p>
</transition>
<button @click="isShow=!isShow">切换</button>
var vm = new Vue({
  el: '#app',
  data() {
    return {
      isShow: true
    }
  },
  methods: {
    handelBeforeEnter(el) {
      el.style.color = 'red';
      console.log('before enter');
    },
    handleEnter(el,done) {
      setTimeout(() => {
        el.style.color = 'green';
        done();
        console.log('enter');
      }, 1500)
    },
    handleAfterEnter(el) {
      console.log('after enter');
    },

    handleBeforeLeave(el) {
      el.style.color = 'yellow';
      console.log('before leave');
    },
    handleLeave(el,done) {
      setTimeout(() => {
        el.style.color = 'blue';
        done();
        console.log('leave');
      }, 1000)
    },
    handleAfterLeave(el) {
      console.log('after leave');
    }
  }
})

Vue中列表过渡

::: tip
前面讲到的过渡/动画,全部是一个元素的过渡/动画,或者多个元素中的一个进行过渡/动画,可以使用transition-group组件来结合v-for进行列表的过渡/动画
:::

.item {
  display: inline-block;
  margin-right: 10px;
}
.v-enter,.v-leave-to {
  opacity: 0;
  transform: translateY(30px)
}
.v-enter-active, .v-leave-active {
  transition: all 0.5s;
}
<transition-group>
  <div v-for="(item,index) in list" :key="item" class="item">{{item}}</div>
</transition-group>
<button @click="handleAddClick">添加</button>
var vm = new Vue({
  el: '#app',
  data() {
    return {
      isShow: true,
      list: [1,2,3,4,5]
    }
  },
  methods: {
    handleAddClick() {
      let maxItem = this.list[this.list.length-1];
      this.list.push(maxItem+1);
    }
  },
})

评论