Angular 6中*ngIf搭配transition动画失效问题求助
Angular Animation Transition Fails with *ngIf in Option 2
我之前也踩过这个坑!问题根源出在*ngIf的工作逻辑上:当它的值变为false时,会直接把<ul>元素从DOM中彻底移除,而Angular的状态过渡动画需要元素始终存在于DOM中才能完整执行。也就是说,当你点击关闭菜单时,isMenuOpen刚变成false,*ngIf就立刻把列表删掉了,根本没给close状态的动画留出执行时间。
下面给你几个可行的解决方案:
方案1:用[hidden]替代*ngIf
[hidden]只是通过CSS的display: none隐藏元素,元素本身依然保留在DOM中,这样动画就能正常触发状态切换了。修改模板代码:
<ul [hidden]="!isMenuOpen" [@animationOption2]="isMenuOpen ? 'open': 'close'" > <li>Menu Item 1</li> <li>Menu Item 2</li> <li>Menu Item 3</li> </ul>
如果你的<ul>有自定义display样式,可能需要给[hidden]加优先级确保生效:
ul[hidden] { display: none !important; }
方案2:使用Angular动画的void状态与:enter/:leave过渡
这是Angular官方推荐的处理元素进出DOM场景的动画方案,专门适配*ngIf这类会增删DOM的指令。修改你的animationOption2触发器:
trigger('animationOption2', [ state('open', style({ opacity: 1, backgroundColor: 'green' })), transition(':enter', [ style({ opacity: 0, backgroundColor: 'yellow' }), animate(3000) ]), transition(':leave', [ animate(3000, style({ opacity: 0, backgroundColor: 'yellow' })) ]) ])
然后模板里无需再绑定状态字符串,直接关联触发器即可:
<ul *ngIf="isMenuOpen" [@animationOption2]> <li>Menu Item 1</li> <li>Menu Item 2</li> <li>Menu Item 3</li> </ul>
这样当*ngIf添加元素时会触发:enter动画,移除元素时触发:leave动画,完美解决DOM销毁导致的动画失效问题。
方案3:手动延迟DOM移除(不推荐)
如果你非要保留原来的状态绑定逻辑,可以在切换isMenuOpen时先触发close动画,等动画完成后再移除元素。修改toggleMenu方法:
// 新增一个变量控制*ngIf menuVisible = false; toggleMenu(): void { if (this.isMenuOpen) { // 先切换到close状态 this.isMenuOpen = false; // 等动画完成后隐藏元素 setTimeout(() => { this.menuVisible = false; }, 3000); // 时长和动画保持一致 } else { this.menuVisible = true; // 确保元素渲染后再切换到open状态 setTimeout(() => { this.isMenuOpen = true; }, 0); } }
模板对应修改为:
<ul *ngIf="menuVisible" [@animationOption2]="isMenuOpen ? 'open': 'close'" > <li>Menu Item 1</li> <li>Menu Item 2</li> <li>Menu Item 3</li> </ul>
不过这种方式需要手动管理定时器,代码复杂度高,不如前两种方案优雅。
个人最推荐方案2,它完全贴合Angular动画的设计理念,代码简洁且可靠性高。
内容的提问来源于stack exchange,提问作者ZoomAll
相关产品推荐
相关产品推荐

