vue中的过渡动画

11次阅读

共计 3063 个字符,预计需要花费 8 分钟才能阅读完成。

前言

记一次 vue 组件中使用 transition 和 transition-group 设置过渡动画, 总结来说可分为分为 name 版, js 钩子操作类名版, js 钩子操作行内样式版 …

template 模板结构

  // 单个元素
    <transition name="自定义名字">
      <p v-if="show">hello</p>
    </transition>
  // 列表元素: 注意 group 的直接子元素是 v -for 渲染出来的
    <ul class="list">
      <transition-group name="list">
        <li v-for="(item, index) in gameList" :key="item.id">
          <app-horizontal :itemData="item"></app-horizontal>
        </li>
      </transition-group>
    </ul>

name 版,name 为组件中的属性

 出现的过程: name-enter(初始态) => name-enter-active(中间态) => name-enter-to(终止态)
消失的过程: name-leave => name-leave-active => name-leave-to

以进场过渡动画为例子

 我们可以分别设置 enter 阶段 和 enter-to 阶段的动画
  1. 设置进入时需要过渡的属性
  .name-enter
  {
    opacity: 0;
    transform: translateY(30px)
  }
  2. 然后在 name-enter-active 中设置过渡时间
  .name-enter-active {transition: all .3s;}
  3. 最后在 name-enter-to 中写上终止态属性
    其实终止态的 opacity: 1;transform: none; 是默认的, 可以不用写
  .name-enter-to {
    opacity: 1;
    transform: translateY(0);
  }
  如果要给列表中的元素设置交错的效果, 元素不多的话可以添加 delay 属性
  .name-enter-active:nth-child(3n+1) {transition-delay: 0s;}
  .name-enter-active:nth-child(3n+2) {transition-delay: .1s;}
  .name-enter-active:nth-child(3n+3) {transition-delay: .2s;}
  离场动画同理...

js 钩子实现过渡动画: 通过操作类名; 就是 name 版的 js 实现

// 例如实现上述列表依次显示
  <ul class="list">
    <transition-group
      v-bind:css="false"
      v-on:before-enter="beforeEnter"
      v-on:enter="enter"
      v-on:after-enter="afterEnter">
      <li v-for="(item, index) in gameList" 
        :key="item.id" 
        :data-delay="index*100" 
      >
          <app-horizontal :itemData="item"></app-horizontal>
      </li>
    </transition-group>
  </ul>  
  // 
  methods: {
    // 事先定义上述类名
    // 在 beforeEnter enter afterEnter 钩子中手动操作上述类名
    
    // 初始态
    beforeEnter(dom) {dom.classList.add('list-enter', 'list-enter-active');
    },
    // 中间态
    enter(dom,done) {
      // 通过 setTimeout + dataset 实现过渡
      let delay = dom.dataset.delay;
      setTimeout(function () {dom.classList.remove('list-enter');
        dom.classList.add('list-enter-to');
        // 监听 transitionend 事件
        var transitionend = window.ontransitionend ? "transitionend" : "webkitTransitionEnd";
        dom.addEventListener(transitionend, function onEnd() {
          // 移除事件
          dom.removeEventListener(transitionend, onEnd);
          // 调用 done(), 表示动画已完成
          done()});
      }, delay)
    },
    // 终止态
    afterEnter(dom) {dom.classList.remove('list-enter-to', 'list-enter-active');
    }
  }

js 钩子过渡动画: 通过操作行内属性, 自定义动画

   <ul class="list">
    <transition-group
      v-bind:css="false"
      v-on:before-enter="beforeEnter"
      v-on:enter="enter"
      v-on:after-enter="afterEnter">
      <li v-for="(item, index) in gameList" 
        :key="item.id" 
        :data-delay="index*100"
        data-y = "100%" 
      >
          <app-horizontal :itemData="item"></app-horizontal>
      </li>
    </transition-group>
  </ul>  
  // 对应的操作方法; 添加自定义的 dataset, 给 dom 设置 css 样式; 根据需求添加
   methods: {
     // 初始态
    beforeEnter(dom) {let { x = 0, y = 0, opacity = 0} = dom.dataset;
      dom.style.cssText = `transition: .3s;opacity: ${opacity};transform: translateX(${x}) translateY(${y});`;
    },
    // 中间态
    enter(dom,done) {
      let delay = dom.dataset.delay;
      setTimeout(function () {dom.style.cssText = `transition: .3s;opacity: 1;transform: translateX(0) translateY(0);`;
        // 监听 transitionend 事件
        var transitionend = window.ontransitionend ? "transitionend" : "webkitTransitionEnd";
        dom.addEventListener(transitionend, function onEnd() {dom.removeEventListener(transitionend, onEnd);
             done();});
      }, delay)
    },
    // 终止态
    afterEnter(dom) {dom.style.cssText = "";}
  }

这里记录一下监听 css3 的 animation 动画和 transition 事件:

webkit-animation 动画有三个事件:开始事件: webkitAnimationStart
    结束事件: webkitAnimationEnd
    重复运动事件: webkitAnimationIteration

css3 的过渡属性 transition: 一个事件
    过渡结束: webkitTransitionEnd

正文完
 0