Vue 3 TransitionGroup中scaleY正常但scale/scaleX异常问题求助
问题:Vue TransitionGroup使用scaleX/scale时自动添加translateX导致异常过渡
我使用Vue 3.4.27版本,将TransitionGroup组件用作无序列表。当设置CSS使用scaleY(0)时过渡效果正常,但使用scale(0)或scaleX(0)时,Vue会自动添加translateX(),导致元素在缩放的同时从右侧滑入。我原以为scaleX()应该让元素处于列表的最终位置,然后逐渐横向展开到完整尺寸,但实际效果并非如此。
组件代码
<TransitionGroup name="grow-y" tag="ul" class="container" appear > <li v-for="(name, index) in names" :key="index"> {{name}} <button @click="names.splice(index, 1);">-</button> </li> </TransitionGroup> <hr> <div>Using scaleX()</div> <transition-group name="grow-x" tag="ul" class="container" appear > <li v-for="(name, index) in names" :key="index"> {{name}} <button @click="names.splice(index, 1);">-</button> </li> </transition-group>
CSS代码
.grow-x-enter, .grow-x-leave-to, .grow-x-enter-from { transform: scaleX(0); opacity: 1; position: absolute; left: 0; } .grow-y-enter, .grow-y-leave-to, .grow-y-enter-from { transform: scaleY(0); opacity: 1; } /** all transitions will share the animation types */ .grow-x-enter-active, .grow-x-leave-active, .grow-x-move, .grow-y-enter-active, .grow-y-leave-active, .grow-y-move { transition: all 5s cubic-bezier(0.55, 0, 0.1, 1); }
解决思路
问题根源
TransitionGroup的move过渡会自动计算元素的位置偏移并添加translate变换。当元素初始状态为scaleX(0)时,宽度被压缩为0,Vue计算位置时会错误认为元素需要从右侧移动到目标位置,因此自动添加translateX。而scaleY(0)不影响元素宽度,所以位置计算不受干扰。
方案1:禁用move过渡(最简单)
如果不需要列表项删除/排序时的位置移动过渡,可以去掉.grow-x-move的transform过渡:
.grow-x-move { /* 仅过渡opacity,避免干扰scaleX动画 */ transition: opacity 5s cubic-bezier(0.55, 0, 0.1, 1); }
方案2:调整变换原点+移除绝对定位
默认transform-origin是元素中心,scaleX(0)会让元素向两侧收缩,导致宽度为0时位置偏移。将变换原点设为左侧,同时移除破坏布局的绝对定位:
.grow-x-enter, .grow-x-leave-to, .grow-x-enter-from { transform: scaleX(0); opacity: 1; transform-origin: left center; /* 从左侧开始缩放 */ /* 移除position:absolute,避免脱离文档流 */ }
方案3:自定义过渡钩子(保留move过渡)
如果需要保留列表项的位置移动动画,可以通过过渡钩子手动控制初始状态,绕过Vue的自动位置计算:
<transition-group name="grow-x" tag="ul" class="container" appear @before-enter="(el) => { el.style.transform = 'scaleX(0)' el.style.transformOrigin = 'left center' }" @enter="(el, done) => { el.style.transform = '' el.offsetWidth // 触发重绘,确保动画生效 done() }" > <li v-for="(name, index) in names" :key="index"> {{name}} <button @click="names.splice(index, 1);">-</button> </li> </transition-group>
内容的提问来源于stack exchange,提问作者Bob Ramsey
相关产品推荐
相关产品推荐

