2021.11.28 vue 过渡和动画(7)

vue过渡和动画

过渡:从一种状态过渡到另外一种状态,只有两种状态,一般只需要我们去做两个关键帧,其他的关键帧是由计算机帮我们生成的

动画:多个关键帧,多段,多状态,我们可以去定义自己的关键帧

我们先来回顾一下css3的过渡和动画

动画:

<style>
  @keyframes move {
    0% {
      transform: translateX(100px);
    }

    50% {
      transform: translateX(50px);
    }

    100% {
      transform: translateX(0px);
    }
  }

  .animation {
    animation: move 3s;
  }
</style>
<body>
  <div id='app'>
    <div class="animation">
      <h1>hello world</h1>
    </div>

    <div :class="animate">
      <h1>hello world</h1>
    </div>
    <button @click='fn'>按钮</button>
  </div>

  <script src='./js/vue.js'></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        animate: {
          animation: true
        }
      },
      methods: {
        fn() {
          this.animate.animation = !this.animate.animation
        }
      }
    })
  </script>
</body>

过渡:

<style>
  .bgc_pink {
    background-color: pink;
  }

  .bgc_blue {
    background-color: skyblue;
  }

  .transition {
    transition: 2s linear;
  }
</style>

<body>
  <div id='app'>
    <div :class='animate'>
      <h1>are you ok?</h1>
    </div>
    <button @click='fn'>按钮</button>
  </div>

  <script src='./js/vue.js'></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        animate: {
          transition: true,
          bgc_pink: true,
          bgc_blue: false,
        }
      },
      methods: {
        fn() {
          this.animate.bgc_pink = !this.animate.bgc_pink,
            this.animate.bgc_blue = !this.animate.bgc_blue
        }
      }
    })
  </script>
</body>

vue单元素的过渡

Vue 提供了 transition的封装组件,在下列情形中,可以给任何元素和组件添加进入/离开过渡

  1. 条件渲染 (使用 v-if)
  2. 条件展示 (使用 v-show)
  3. 动态组件
  4. 组件根节点
<style>
  .fade-enter-active,
  .fade-leave-active {
    transition: opacity .5s;
  }

  .fade-enter,
  .fade-leave-to {
    opacity: 0;
  }
</style>

<body>
  <div id='app'>
    <button @click='show=!show'>切换状态</button>
    <transition name='fade'>
      <p v-if='show'>hello world</p>
    </transition>

  </div>

  <script src='./js/vue.js'></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        show: true
      }
    })
  </script>
</body>

当插入或删除包含在transition 组件中的元素时,Vue 将会做以下处理:

  1. 自动嗅探目标元素是否应用了 CSS 过渡或动画,如果是,在恰当的时机添加/删除 CSS 类名。
  2. 如果过渡组件提供了 JavaScript 钩子函数( 就是在一个生命周期的各个阶段给我们提供的操作切入口 ),这些钩子函数将在恰当的时机被调用。
  3. 如果没有找到 JavaScript 钩子并且也没有检测到 CSS 过渡/动画,DOM 操作 (插入/删除) 在下一帧中立即执行。(注意:此指浏览器逐帧动画机制,和 Vue 的 nextTick 概念不同)
<style>
  .v-enter {
    opacity: 0;
  }

  .v-enter-active {
    transition: opacity 2s ease;
  }

  .v-enter-to {
    opacity: 1;
  }

  .v-leave {
    opacity: 1;
  }

  .v-leave-active {
    transition: opacity 2s ease;
  }

  .v-leave-to {
    opacity: 0;
  }
</style>

<body>
  <div id='app'>
    <!-- <div v-if='show'>
      <h1>你好,世界</h1>
    </div>
    <button @click='show=!show'>按钮</button> -->

    <button @click='show=!show'>按钮</button>
    <transition>
      <div v-if='show'>
        <h1>你好,世界</h1>
      </div>
    </transition>
  </div>

  <script src='./js/vue.js'></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        show: true
      }
    })
  </script>
</body>

在进入/离开的过渡中,会有6 个 class切换。

1.v-enter-active:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。

2.v-enter:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。

3.v-enter-to:定义进入过渡的结束状态。在元素被插入之后下一帧生效(与此同时 v-enter被移除),在过渡/动画完成之后移除。

4.v-leave-active:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。

5.v-leave:定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。

6.v-leave-to:定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效(与此同时 v-leave被删除),在过渡/动画完成之后移除。

vue单元素动画

下面我们可以试试使用主动式的动画, CSS 主动式动画用法同 CSS 过渡

<style>
  @keyframes move {
    0% {
      transform: translateX(-100px);
    }

    50% {
      transform: translateX(-50px);
    }

    100% {
      transform: translateX(0);
    }
  }

  .v-enter-active {
    animation: move 2s linear;
  }

  .v-leave-active {
    animation: move 2s reverse;
  }
</style>

<body>
  <div id='app'>
    <button @click='show=!show'>按钮</button>
    <transition>
      <h1 v-if='show'>哈哈哈</h1>
    </transition>
  </div>
  <script src='./js/vue.js'></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        show: false
      }
    })
  </script>
</body>

主动式动画比起触发式动画, 少了enter, leave-to的定义.但是这个定义可以在关键帧动画里面进行定义.

enter就是0% 的帧,enter-to就是100%的帧

leave就是100%的帧, leave-to就是0%的帧(就是动画倒过来)

单元素/组件的动画应用自定义过渡的类名

我们可以通过以下特性来自定义过渡类名:

enter-class
enter-active-class
enter-to-class
leave-class
leave-active-class
leave-to-class
他们的优先级高于普通的类名,这对于 结合一起使用Vue 的过渡系统和其他第三方 CSS 动画库,如 Animate.css 或是layui的CSS动画体系结合使用十分有用。

<style>
  @keyframes move {
    0% {
      transform: translateX(-100px);
    }

    50% {
      transform: translateX(-50px);
    }

    100% {
      transform: translateX(0);
    }
  }

  .fade-enter-active {
    animation: move 2s linear;
  }

  .fade-leave-active {
    animation: move 2s reverse;
  }

  .come {
    animation: move 2s linear;
  }
  .out{
    animation: move 2s reverse;
  }
</style>

<body>
  <div id='app'>
    <button @click=fn>按钮</button>
    <transition>
      <h1 v-if='show'>哈哈哈</h1>
    </transition>
    <hr>
    <transition name='fade'>
      <h1 v-if='show'>哈哈哈</h1>
    </transition>
    <hr>
    <transition name='laowang' enter-active-class='come' leave-active-class='out'>
      <h1 v-if='show'>嘿嘿嘿</h1>
    </transition>
  </div>
  <script src='./js/vue.js'></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        show: false,
      },
      methods: {
        fn() {
          this.show = !this.show
        }
      }
    })
  </script>
</body>

简单来说,原理和上面我们自己写的动画一毛一样, 就只是把自己做的动画代码改成别人的了.

多元素的过渡

<div id='app'>
  <button @click='show=!show'>按钮</button>
  <transition name='fade'>
    <div v-if='show'>
      <h1>hello world</h1>
    </div>
    <div v-if='show'>
      <h1>你好,世界</h1>
    </div>
  </transition>
</div>

这样是不行滴,transition标签里面是不阔以直接放俩元素的, 这样的话, 第二个元素会直接忽略,而且还会有一个警告

  <div id='app'>
    <button @click='show=!show'>按钮</button>
    <transition name='fade'>
      <div v-if='show'>
        <h1>hello world</h1>
      </div>
      <div v-else>
        <h1>你好,世界</h1>
      </div>
    </transition>
  </div>

这样也是不行滴, 虽说咱们现在里面一次只会出现一个元素, 但是这两个元素是同名标签, 所以只是单纯的出现了元素内容的替换,木有动画效果

当有相同标签名的元素切换时,需要通过 key 特性设置唯一的值来标记以让 Vue 区分它们,否则 Vue 为了效率只会替换相同标签内部的内容。即使在技术上没有必要,给在 组件中的多个元素设置 key 是一个更好的实践。

<transition name='fade'>
  <div v-if='show' key='one'>
    <h1>hello world</h1>
  </div>
  <div v-else key='two'>
    <h1>你好,世界</h1>
  </div>
</transition>

这样的多个元素的显示效果之间的过渡, 是存在一个重叠的时间的上一个元素的消失和下一个元素的显示, 这两个动画是同步进行的, 所以看上去像是有两个元素都显示出来了

在一些场景中,也可以通过给同一个元素的 key 特性设置不同的状态来代替 v-if 和 v-else,上面的例子可以重写为下面的示例, 效果是一样的:

<transition name='fade'>
  <div :key='show'>
    <h1>{{show?'hello world':'你好,世界'}}</h1>
  </div>
</transition>

多元素的过渡状态重叠的解决方案

这种写法会导致两个元素在某一时刻同时出现

<transition name='fade'>
  <div v-if='show' key='one'>
    <h1>hello world</h1>
  </div>
  <div v-else key='two'>
    <h1>你好,世界</h1>
  </div>
</transition>

同时生效的进入和离开的过渡不能满足所有要求,所以 Vue 给transition标签提供了 过渡模式

  1. in-out:新元素先进行过渡,完成之后当前元素过渡离开
  2. out-in:当前元素先进行过渡,完成之后新元素过渡进入
<transition name='fade' mode='in-out'>
  <div v-if='show' key='one'>
    <h1>hello world</h1>
  </div>
  <div v-else key='two'>
    <h1>你好,世界</h1>
  </div>
</transition>

多组件的过渡

多个组件的过渡简单很多 - 我们不需要使用key 特性。相反,我们只需要使用动态组件

<style>
  .fade-enter,
  .fade-leave-to {
    opacity: 0;
  }

  .fade-enter-active,
  .fade-leave-active {
    transition: opacity 2s ease;
  }
</style>

<body>
  <div id='app'>
    <button @click='fn(tab)' v-for='tab in tabs' :key='tab'>{{tab}}</button>
    <transition name='fade' , mode='out-in'>
      <component :is='now_tab'></component>
    </transition>
    <!-- <component is='tab_zhuye'></component> -->
  </div>

  <script src='./js/vue.js'></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        tabs: ['zhuye', 'keji', 'yinyue'],
        now_tab: 'tab_zhuye'
      },
      methods: {
        fn(tab) {
          return this.now_tab = 'tab_' + tab
        }
      },
      components: {
        tab_zhuye: {
          template: '<div><h1>主页组件</h1></div>'
        },
        tab_keji: {
          template: '<div><h1>科技组件</h1></div>'
        },
        tab_yinyue: {
          template: '<div><h1>音乐组件</h1></div>'
        },
      }
    })
  </script>
</body>

列表的过渡

怎么同时渲染整个列表,比如使用v-for ?在这种场景中,使用 组件

在我们深入例子之前,先了解关于这个组件的几个特点:

  1. 不同于 ,它会以一个真实元素呈现:默认为一个 。你也可以通过 tag 特性更换为其他元素。( 注意, 此处是指 transition-group元素本身)
  2. 过渡模式不可用,因为我们不再相互切换特有的元素。
  3. 内部元素 总是需要 提供唯一的 key 属性值。
  4. CSS 过渡的类将会应用在内部的元素中,而不是这个组/容器本身。
<style>
  span {
    display: inline-block;
    margin-right: 20px;
    font-size: 30px;
  }

  .v-enter {
    opacity: 0;
    transform: translateY(30px);
  }

  .v-enter-active {
    transition: 1s ease-in;
  }

  .v-enter-to {
    opacity: 1;
    transform: translateY(0);
  }

</style>

<body>
  <div id='app'>
    <div>
      <transition-group>
        <span v-for='item in list' :key='item'>
          {{item}}
        </span>
      </transition-group>
      <button @click='fn'>add</button>
    </div>
  </div>

  <script src='./js/vue.js'></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        list: [1, 2, 3],
      },
      methods: {
        fn() {
          this.list.push(this.list.length + 1)
        }
      }
    })
  </script>
</body>

数据的过渡

Vue 的过渡系统提供了非常多简单的方法设置进入、离开和列表的动效。那么对于数据元素本身的动效呢,比如:

1.数字和运算

2.颜色的显示

3.节点的位置

4.元素的大小和其他的属性

这些数据要么本身就以数值形式存储,要么可以转换为数值。有了这些数值后,我们就可以结合Vue 的响应式和组件系统,使用第三方库来实现切换元素的过渡状态。

<body>
  <div id='app'>
    <button @click='fn'>按钮</button>
    <div>{{animate_num}}</div>
  </div>

  <script src='./js/vue.js'></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        num: 1,
        animate_num: 1
      },
      methods: {

        fn() {
          this.num = 10
          if (this.animate_num < this.num) {
            const set_id = setInterval(() => {
              this.animate_num += 1;
              if (this.animate_num === this.num) {
                clearInterval(set_id)
              }
            }, 100);
          }
        }
      }
    })
  </script>
</body>
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值