Vue中等待DOM更新完成触发菜单过渡动画的问题咨询
问题根本原因
Vue 的$nextTick仅保证虚拟DOM对应的真实DOM更新已提交,不会等待浏览器完成样式计算、重排重绘的完整渲染流水线。你两次修改menuStyles的操作会被浏览器的渲染优化机制合并,最终相当于直接把--int-menu-height设为0,没有前后状态差,自然不会触发过渡动画,transitionend也不会执行。
可行解决方案
方案1:强制触发浏览器重排(最简单通用)
主动读取DOM的布局属性会强制浏览器立即计算并应用当前已提交的样式变更,不会和后续修改合并:
const comp = this; const menu = this.$refs.menu; const menuHeight = this.$refs.menuHeight.clientHeight+'px'; // 将原本为auto的属性设置为菜单实际高度 this.menuStyles = { '--int-menu-height': menuHeight }; // 强制触发重排,让浏览器立即应用上面的样式变更 void menu.offsetHeight; // 直接设置为0即可触发过渡 this.menuStyles = { '--int-menu-height': 0 }; menu.addEventListener('transitionend', function closeMenu(e) { // 建议加属性判断,避免元素上其他过渡属性误触发回调 if(e.propertyName === 'height' || e.propertyName === '--int-menu-height') { comp.isMenuOpen = false; menu.removeEventListener('transitionend', closeMenu); } });
方案2:双requestAnimationFrame等待帧刷新
requestAnimationFrame会在浏览器下一帧渲染前执行,嵌套两次即可保证第一次样式变更已经被应用到当前帧:
const comp = this; const menu = this.$refs.menu; const menuHeight = this.$refs.menuHeight.clientHeight+'px'; this.menuStyles = { '--int-menu-height': menuHeight }; requestAnimationFrame(() => { requestAnimationFrame(() => { this.menuStyles = { '--int-menu-height': 0 }; }) }); // transitionend监听逻辑同上
注意事项
请确保菜单元素的过渡配置已经正确关联自定义属性,示例如下:
.menu { height: var(--int-menu-height); transition: --int-menu-height 0.3s ease; /* 部分低版本浏览器不支持自定义属性过渡,可直接过渡height属性 */ /* transition: height 0.3s ease; */ }
内容的提问来源于stack exchange,提问作者Nachtfunke
相关产品推荐
相关产品推荐

