Skip to content

TransitionGroup

<TransitionGroup> 是一个内置组件,用于对 v-for 列表中的元素或组件的插入、移除和顺序改变添加动画效果。

1.组件属性

<TransitionGroup> 拥有与 <Transition> 除了 mode 以外所有的 props,并增加了两个额外的 props:

<TransitionGroup> 抛出与 <Transition> 相同的事件。

ts
interface TransitionGroupProps extends Omit<TransitionProps, 'mode'> {
  /**
   * 如果未定义,则渲染为片段 (fragment)。
   */
  tag?: string
  /**
   * 用于自定义过渡期间被应用的 CSS class。
   * 在模板中使用 kebab-case,例如 move-class="xxx"
   */
  moveClass?: string
}

2.和Transition的区别

<TransitionGroup> 支持和 <Transition> 基本相同的 props、CSS 过渡 class 和 JavaScript 钩子监听器,但有以下几点区别:

  • 默认情况下,它不会渲染一个容器元素。但你可以通过传入 tag prop 来指定一个元素作为容器元素来渲染。
  • 过渡模式在这里不可用,因为我们不再是在互斥的元素之间进行切换。
  • 列表中的每个元素都必须有一个独一无二的 key attribute。
  • CSS 过渡 class 会被应用在列表内的元素上,而不是容器元素上。

WARNING

注意,每个 <transition-group> 的子节点必须有独立的 key,动画才能正常工作

当在 DOM 内模板中使用时,组件名需要写为 <transition-group>

3.进入/离开动画

这里是 <TransitionGroup> 对一个 v-for 列表添加进入 / 离开动画的示例:

vue
<TransitionGroup name="list" tag="ul">
  <li v-for="item in items" :key="item">
    {{ item }}
  </li>
</TransitionGroup>
css
.list-enter-active,
.list-leave-active {
  transition: all 0.5s ease;
}
.list-enter-from,
.list-leave-to {
  opacity: 0;
  transform: translateX(30px);
}

    4.移动动画

    上面的示例有一些明显的缺陷:当某一项被插入或移除时,它周围的元素会立即发生“跳跃”而不是平稳地移动。我们可以通过添加一些额外的 CSS 规则来解决这个问题:

    css
    .list-move, /* 对移动中的元素应用的过渡 */
    .list-enter-active,
    .list-leave-active {
      transition: all 0.5s ease;
    }
    
    .list-enter-from,
    .list-leave-to {
      opacity: 0;
      transform: translateX(30px);
    }
    
    /* 确保将离开的元素从布局流中删除
      以便能够正确地计算移动的动画。 */
    .list-leave-active {
      position: absolute;
    }

    现在看起来有那么一丝丝的顺滑,甚至对整个列表执行洗牌的动画也都非常流畅:

      5.渐进延迟列表动画

      通过在 JavaScript 钩子中读取元素的 data attribute,我们可以实现带渐进延迟的列表动画。首先,我们把每一个元素的索引渲染为该元素上的一个 data attribute:

      vue
      <input type="text" v-model="query" class="ipt" />
      <TransitionGroup
        tag="ul"
        :css="false"
        @before-enter="onBeforeEnter"
        @enter="onEnter"
        @leave="onLeave"
      >
        <li
          v-for="(item, index) in computedList"
          :key="item.msg"
          :data-index="index"
        >
          {{ item.msg }}
        </li>
      </TransitionGroup>

      接着,在 JavaScript 钩子中,我们基于当前元素的 data attribute 对该元素的进场动画添加一个延迟。以下是一个基于 GSAP library 的动画示例:

      js
      const list = [
      	{ msg: 'Bruce Lee' },
      	{ msg: 'Jackie Chan' },
      	{ msg: 'Chuck Norris' },
      	{ msg: 'Jet Li' },
      	{ msg: 'Kung Fury' },
      ]
      
      const query = ref('')
      const computedList = computed(() => {
      	return list.filter(item => item.msg.toLowerCase().includes(query.value))
      })
      function onEnter(el, done) {
      	gsap.to(el, {
      		opacity: 1,
      		height: '1.6em',
      		delay: el.dataset.index * 0.15,
      		onComplete: done,
      	})
      }
      function onBeforeEnter(el) {
      	el.style.opacity = 0
      	el.style.height = 0
      }
      function onLeave(el, done) {
      	gsap.to(el, {
      		opacity: 0,
      		height: 0,
      		delay: el.dataset.index * 0.15,
      		onComplete: done,
      	})
      }
      • Bruce Lee
      • Jackie Chan
      • Chuck Norris
      • Jet Li
      • Kung Fury

      MIT Licensed