vue 过渡和动画、垂直居中

transition 是一个封装好的组件, 作用是自动侦测它的子组件有没有被添加相应的 css/动画规则, 如果有, 则自动给子组件加上相应的类名.

类名由前缀 + 后缀组成, 前缀和 transition 的 name 属性一致, name 属性缺失的话则前缀默认为 v, 前缀+后缀的类名为:

  • v-enter: 该类名在元素被插入dom前添加, 插入 dom 后的下一帧移除
  • v-enter-active: 在元素被插入前添加, 动画完成后移除
  • v-enter-to: 在元素被插入的下一帧添加(以此同时 v-enter 被移除), 动画完成后移除
  • v-leave: 离开过度被触发时生效, 下一帧被移除(所以只存活了一帧?)
  • v-leave-active: 离开过度生效时的状态, 动画完成后移除
  • v-leave-to: 定义过渡结束时的状态, 动画完成后移除

v-enter-to/v-leave 的状态如果不做定义, 我的理解是元素的表现就和静止时一样. 所以一般不需要做额外的定义.

如果定义一个进入/离开对称的动画, 需要定义的是两组数据: - v-enter/v-leave-to: 进入的初始化状态和离开的最终状态, 元素的状态将从 v-enter 变为 v-enter-to(或者默认的静止状态); v-leave(或者默认的静止状态) => v-leave-to - v-enter-active/v-leave-active: 前一组数据已经能确定元素的开始和结束状态, 这一组数据定义了变化的过程, 如过渡的过程时间, 延迟和曲线函数

如果配合第三方的动画库, 那么需要自定义过度的类名:

  • enter-class
  • enter-active-class
  • enter-to-class
  • leave-class
  • leave-active-class
  • leave-to-class

列表的过渡效果

如果需要对列表做过渡效果, 如果用到 transition-group 组件。 但是如果仅仅是定义之前提到的两组 css 规则, 单元素的进入、淡出过渡效果很平滑, 但是跟相邻元素之间的过渡效果却很生硬。添加元素时其他元素会立刻腾出位置, 然后新元素开始进入过渡。删除元素时被删元素离开动画结束后, 相邻的元素立刻把位置补上。

为了让其他元素的让位、补位的过程平滑, 可以设置 v-move 类的规则, 一般来说简单设置:

v-move {
  transition: all 1s;
}

这样就解决了进入的时候“让位”这个动作很突然的问题。但是“补位”等到离开过度结束才开始的问题还没解决。原因在于被删除的元素在过度期间一直占用着文档流的空间, 如果让被删元素脱离文档流, 那么问题解决。官方的文档这么写:

v-leave-active {
  position: absolute;
}

但是一个绝对定位的但是又没有设置 top/bottom/left/right 的元素, 它的位置是什么地方呢?

不设值和设置为auto, 效果一样的。它最终的位置在“它在文档中的最初始位置”, 初始位置的意思是定位为 position, float 为 none 的位置。如 demo

这下动画开始的时候被删元素就脱离了文档流, 它之后的元素就可以马上开始补位的过渡了。

延伸一下, 如果一个绝对定位的元素 top/bottom/left/right 四个值都是 0 又将如何? 如果该元素没有宽高,那么那将占满父元素。否则的话属于过分约束, left/top 将起主导作用, 忽略 right/bottom。

再皮一点, 将四个属性设置为0, 再设置 margin: auto auto, 那么可以将元素居中。为什么? 规范 里说得非常清楚

至于为什么非绝对定位的 margin: auto auto 为什么不能让元素垂直居中,我觉得是因为垂直方向上可以同时存在多个块级元素,如果两个都利用 margin 能达到垂直居中的效果, 那不是两个重叠了吗?static 定位是不会发生重叠这种事情的。

需要进一步了解的内容