Vue(九)-多元素动画效果

723 阅读4分钟

一、原生标签的过渡

我们讨论多个组件的过渡,对于原生标签可以使用 v-if/v-else。

<transition>
  <button v-if="isEditing" key="save">
    Save
  </button>
  <button v-else key="edit">
    Edit
  </button>
</transition>

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

在一些场景中,也可以通过给同一个元素的 key attribute 设置不同的状态来代替 v-ifv-else,上面的例子可以重写为:

<transition>
  <button v-bind:key="isEditing">
    {{ isEditing ? 'Save' : 'Edit' }}
  </button>
</transition>

二、过渡模式

此时的两个button标签,save淡出的同时,edit淡入。一个离开过渡的时候另一个开始进入过渡。这是 <transition> 的默认行为 - 进入和离开同时发生。

可以用绝对定位把两个按钮重合起来(轮播)

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

  • in-out:新元素先进行过渡,完成之后当前元素过渡离开。

  • out-in:当前元素先进行过渡,完成之后新元素过渡进入。

三、动态组件

有的时候,在不同组件之间进行动态切换是非常有用的,比如在一个多标签的界面里

上述内容可以通过 Vue 的 <component> 元素加一个特殊的 is attribute来实现:

<component v-bind:is="currentTabComponent"></component>

在上述示例中,currentTabComponent 可以包括

  • 已注册组件的名字
  • 一个组件的选项对象

四、过渡组件

<transition name="component-fade" mode="out-in">
  <component v-bind:is="view"></component>
</transition>

即可实现组件的过渡

五、列表过渡

目前为止,关于过渡我们已经讲到:

  • 单个节点
  • 同一时间渲染多个节点中的一个

我们现在想要渲染整个列表,该怎么办

<div id="list-demo" class="demo">
  <button v-on:click="add">Add</button>
  <button v-on:click="remove">Remove</button>
  <transition-group name="list" tag="p">
    <span v-for="item in items" v-bind:key="item" class="list-item">
      {{ item }}
    </span>
  </transition-group>
</div>

new Vue({
  el: '#list-demo',
  data: {
    items: [1,2,3,4,5,6,7,8,9],
    nextNum: 10
  },
  methods: {
    randomIndex: function () {
      return Math.floor(Math.random() * this.items.length)
    },
    add: function () {
      this.items.splice(this.randomIndex(), 0, this.nextNum++)
    },
    remove: function () {
      this.items.splice(this.randomIndex(), 1)
    },
  }
})
.list-item {
  display: inline-block;
  margin-right: 10px;
}
.list-enter-active, .list-leave-active {
  transition: all 1s;
}
.list-enter, .list-leave-to
/* .list-leave-active for below version 2.1.8 */ {
  opacity: 0;
  transform: translateY(30px);
}

1. 不同于 <transition>,它会以一个真实元素呈现:默认为一个 <span>。你也可以通过 tagattribute 更换为其他元素。

2. 过渡模式不可用,因为我们不再相互切换特有的元素。
3. 内部元素总是需要 提供唯一的 key 属性值。
4. CSS 过渡的类将会应用在内部的元素中,而不是这个组/容器本身。

tag:

由于transition-group标签默认需要子组件是v-for,但是又需要一个对象来吧列表包起来,所以需要tag这个属性

两个类

  1. transition-group的类是为了添加列表项目的动画
  2. 列表的类是为了添加列表加进来后的样式,以及已经存在列表的样式

这个例子有个问题,当添加和移除元素的时候,周围的元素会瞬间移动到他们的新布局的位置,而不是平滑的过渡,我们下面会解决这个问题。

六、列表的排序过渡

<transition-group> 组件还有一个特殊之处。不仅可以进入和离开动画,还可以改变定位。要使用这个新功能只需了解新增的 v-move attribute,它会在元素的改变定位的过程中应用。像之前的类名一样,可以通过 name 属性来自定义前缀,也可以通过 move-class 属性手动设置。

.flip-list-move {
  transition: transform 1s;
}

这样即可

 <transition-group name="list-complete" tag="p">
    <span
      v-for="item in items"
      v-bind:key="item"
      class="list-complete-item"
    >
      {{ item }}
    </span>
  </transition-group>

.list-complete-item {
  transition: all 1s;
  display: inline-block;
  margin-right: 10px;
}

列表的一切变动都会有动画过渡

需要注意的是使用 FLIP 过渡的元素不能设置为 display: inline 。作为替代方案,可以设置为 display: inline-block 或者放置于 flex 中