Vue封装可复用TransitionGroup组件过渡动画未按预期生效
Vue单文件组件的scoped样式实现隔离的逻辑是:给当前组件自身渲染的DOM元素加唯一哈希属性(类似data-v-7ba5bd90),同时给所有样式选择器末尾追加对应的属性选择器,确保样式只会命中当前组件的元素。
你封装的过渡组件中,<slot>位置渲染的li元素是父组件ProductList的模板内容,属于父组件渲染的DOM,不会被加上当前过渡组件的哈希标记。因此你写在过渡组件scoped块里的.list-enter-from这类选择器,编译后会变成.list-enter-from[data-v-7ba5bd90],根本匹配不到插槽传进来的li元素,动画自然触发不了。而把同样的样式写在ProductList的scoped块里时,li元素带有ProductList的哈希属性,选择器可以正常匹配,所以动画能正常运行。
方案1:用深度选择器穿透作用域(推荐)
使用:deep()伪类修改封装组件内的过渡样式,让选择器可以匹配到插槽传入的子元素,既保留样式隔离的特性,又不需要在业务组件重复写样式,还能用上你定义的duration属性:
<template> <transition-group name="list" tag="ul"> <slot></slot> </transition-group> </template> <script> export default { props: { duration: { type: Number, default: 2, }, }, }; </script> <style scoped> :deep(.list-enter-from) { opacity: 0; } :deep(.list-enter-active) { transition: opacity v-bind(duration + 's') ease-in; } :deep(.list-enter-to) { opacity: 1; } </style>
方案2:使用全局样式
如果需要在项目多个地方复用这套过渡效果,可以去掉<style>标签的scoped属性,把过渡样式设为全局:
<style> /* 无scoped标识,样式全局生效 */ .list-enter-from { opacity: 0; } .list-enter-active { transition: opacity 1s ease-in; } .list-enter-to { opacity: 1; } </style>
注意全局样式容易出现类名冲突,建议给过渡名加专属前缀,比如把name="list"改成name="custom-fade",对应类名同步修改即可。
额外提醒:使用
<transition-group>时一定要给循环渲染的子元素设置唯一key,否则过渡动画会出现异常,你当前的代码里已经给li绑定了product.id作为key,这部分符合要求。
内容的提问来源于stack exchange,提问作者qweezz

