Angular 4中动态追加DOM元素时(click)事件失效问题
解决Angular 4中jQuery追加DOM后(click)事件失效的问题
这个问题我太熟啦!你遇到的核心问题是Angular不会识别通过jQuery直接插入DOM的内容——因为Angular的事件绑定、指令这些都是在模板编译阶段处理的,你用jQuery硬塞进去的<tr>和(click)指令,Angular根本没机会编译它们,自然触发不了assign()函数。
下面给你两种解决方案,优先推荐第一种(完全符合Angular的设计思路):
方案一:用Angular的数据绑定替代jQuery操作DOM
这是最标准的做法,完全不需要jQuery介入。我们通过控制一个数组来动态生成表格行,Angular会自动帮我们编译新元素并绑定事件:
- 在组件类里定义存储行数据的数组和
assign方法:
// 组件类代码 export class YourComponent { // 存储表格行的数据 tableRows: Array<{id: number, day: string}> = []; assign(id: number) { console.log(id); } // 调用这个方法来添加新行 addTableRow() { this.tableRows.push({id: 1, day: 'Sunday'}); } }
- 在模板里用
*ngFor循环渲染行:
<!-- 模板代码 --> <table id="time_table_table"> <tbody> <tr *ngFor="let row of tableRows" [attr.data-id]="row.id"> <td>{{row.day}}<a (click)="assign(row.id)">Assign</a></td> </tr> </tbody> </table>
之后你只要调用addTableRow()方法,Angular就会自动渲染新的表格行,而且(click)事件能正常触发。
方案二:如果一定要用jQuery(不推荐),手动让Angular编译DOM
如果你因为某些原因必须用jQuery操作DOM,那需要手动让Angular编译新增的元素。不过这种方式比较复杂,而且不符合Angular的最佳实践,仅作参考:
你需要借助Angular的编译相关服务,把新增的DOM元素包装成组件或者让Angular编译这段HTML:
import { Component, ElementRef, ViewChild, Compiler, NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; @Component({ selector: 'your-component', template: '<table id="time_table_table"><tbody #tbody></tbody></table>' }) export class YourComponent { @ViewChild('tbody') tbodyRef: ElementRef; constructor(private compiler: Compiler) {} addRowWithJquery() { // 定义动态行的组件模板 const rowTemplate = ` <tr data-id="1"> <td>Sunday<a (click)="assign(1)">Assign</a></td> </tr> `; // 创建临时组件和模块 @Component({ template: rowTemplate }) class DynamicRowComponent { assign: (id: number) => void; } @NgModule({ imports: [CommonModule], declarations: [DynamicRowComponent] }) class DynamicModule {} // 编译模块并创建组件实例 this.compiler.compileModuleAndAllComponentsAsync(DynamicModule) .then(moduleFactories => { const componentFactory = moduleFactories.componentFactories.find( factory => factory.componentType === DynamicRowComponent ); const componentRef = componentFactory.create(this.tbodyRef.nativeElement.injector); // 绑定父组件的assign方法 componentRef.instance.assign = this.assign.bind(this); // 将组件DOM插入到tbody中 this.tbodyRef.nativeElement.appendChild(componentRef.location.nativeElement); }); } assign(id: number) { console.log(id); } }
这种方式需要额外处理模块和组件的编译,非常繁琐,所以还是优先推荐方案一。
总结一下:Angular是数据驱动的框架,尽量不要用jQuery直接操作DOM,用数据绑定的方式能避免很多这类奇怪的问题,代码也更易维护。
内容的提问来源于stack exchange,提问作者Apurv Chaudhary
相关产品推荐
相关产品推荐

