Angular 9中如何处理动态生成ul li的mouseover与mouseout事件
问题根因
- DOM选择逻辑错误:你使用的
el.nextElementSibling('span')是查找当前li同级的下一个span兄弟节点,但你的span是li的子元素,所以该方法返回null,操作样式自然失效。 - 生命周期时机错误:
ngOnInit执行时组件模板尚未完成DOM渲染,如果你是通过*ngFor动态生成li元素,此时查询到的li集合大概率为空,事件没有成功绑定。 - 原生事件绑定存在隐患:直接调用
addEventListener绑定事件,组件销毁时如果不手动解绑,会导致内存泄漏。
解决方案
方案1:纯CSS实现(最推荐,无JS逻辑)
只需要加两行样式即可实现效果,不需要修改TS和HTML结构,性能最优:
/* 默认隐藏span */ .nav-tabs .item span { display: none; } /* li hover时显示内部的span */ .nav-tabs .item:hover span { display: block; }
方案2:Angular原生事件绑定(适配动态生成li场景)
符合Angular开发规范,不需要手动操作DOM,动态新增/删除li自动生效:
- 修改
app.component.html:
<ul class="nav-tabs"> <!-- 循环生成动态li,绑定hover事件记录当前hover的索引 --> <li class="item" *ngFor="let item of tabList; let i = index" (mouseover)="hoverIdx = i" (mouseout)="hoverIdx = null"> <a>{{item.name}}</a> <!-- 只有当前项被hover时才显示span --> <span *ngIf="hoverIdx === i"> -On </span> </li> </ul>
- 修改
app.component.ts,新增两个变量即可:
export class AppComponent { // 你的动态tab数据,可通过接口赋值 tabList = [{name: 'Test1'}, {name: 'Test2'}, {name: 'Test3'}] // 记录当前hover的tab索引 hoverIdx: number | null = null }
方案3:修正你的原生JS写法
如果需要保留手动操作DOM的逻辑,修改如下:
import { AfterViewInit, Component, ElementRef, OnDestroy } from '@angular/core'; @Component({ // 你的原有组件配置 }) export class AppComponent implements AfterViewInit, OnDestroy { constructor(private elRef: ElementRef) {} // 换用ngAfterViewInit生命周期,此时DOM已经渲染完成 ngAfterViewInit() { const liList = this.elRef.nativeElement.querySelectorAll('ul.nav-tabs li'); liList.forEach(el => { el.addEventListener('mouseover', this.handleMouseOver); el.addEventListener('mouseout', this.handleMouseOut); }); } private handleMouseOver(e: Event) { // 查找当前li内部的span元素 const span = (e.currentTarget as HTMLElement).querySelector('span'); if(span) span.style.display = 'block'; } private handleMouseOut(e: Event) { const span = (e.currentTarget as HTMLElement).querySelector('span'); if(span) span.style.display = 'none'; } // 组件销毁时解绑事件,避免内存泄漏 ngOnDestroy() { const liList = this.elRef.nativeElement.querySelectorAll('ul.nav-tabs li'); liList.forEach(el => { el.removeEventListener('mouseover', this.handleMouseOver); el.removeEventListener('mouseout', this.handleMouseOut); }); } }
内容的提问来源于stack exchange,提问作者Sansara
相关产品推荐
相关产品推荐

