Angular 11 动态右键菜单点击事件无法传参及绑定问题咨询
解决方案
现有代码问题说明
- 子组件未使用Angular标准的自定义事件机制,和框架的事件绑定逻辑不兼容
- 直接给实例属性赋值处理函数时没有做参数闭包,也没有修正this指向,导致无法传入openContextMenu的event参数,且处理函数内部this指向错误
推荐实现方案(符合Angular规范)
1. 修正右键菜单项组件代码
import { Component, Input, Output, EventEmitter, HostListener } from '@angular/core'; @Component({ selector: 'contextmenu-item', template: `<span>{{ label }}</span>`, styleUrls: ['./contextmenu-item.component.scss'] }) export class ContextmenuItemComponent { @Input() public label: string = "default"; // 定义自定义点击事件,支持向外传递任意参数 @Output() public itemClick = new EventEmitter<void>(); // 监听宿主点击事件,触发自定义事件 @HostListener('click') public handleHostClick(): void { this.itemClick.emit(); } }
2. 动态创建组件时绑定事件并传参
订阅子组件的自定义事件即可直接传入当前作用域下的event参数,箭头函数会自动绑定父组件的this指向,无需额外处理:
@ViewChild("contextmenu") $contextmenuComponent!: ContextmenuComponent; @ViewChild("contextRef", {read: ViewContainerRef}) $ref!: ViewContainerRef; openContextMenu(event: IGridCellEventArgs, documentGridBoundary: HTMLDivElement) { this.$contextmenuComponent.show(event, documentGridBoundary); const componentFactory = this.factory.resolveComponentFactory(ContextmenuItemComponent); const item1 = this.$ref.createComponent(componentFactory); item1.instance.label = "Open"; // 订阅点击事件,传入当前event参数 const clickSub = item1.instance.itemClick.subscribe(() => { this.contextOpenDocument(event); }); // 组件销毁时取消订阅,避免内存泄漏 item1.onDestroy(() => clickSub.unsubscribe()); }
轻量方案(无需修改子组件)
如果不想改动现有子组件代码,也可以直接绑定组件原生DOM的点击事件:
openContextMenu(event: IGridCellEventArgs, documentGridBoundary: HTMLDivElement) { this.$contextmenuComponent.show(event, documentGridBoundary); const componentFactory = this.factory.resolveComponentFactory(ContextmenuItemComponent); const item1 = this.$ref.createComponent(componentFactory); item1.instance.label = "Open"; // 拿到组件原生DOM元素,绑定点击事件 const itemDom = item1.location.nativeElement as HTMLElement; const clickHandler = () => this.contextOpenDocument(event); itemDom.addEventListener('click', clickHandler); // 组件销毁时移除事件监听 item1.onDestroy(() => itemDom.removeEventListener('click', clickHandler)); }
补充问题解答:动态组件绑定类似(click)="func()"的事件
Angular中动态组件的事件绑定有两种标准实现:
- 子组件通过
@Output定义EventEmitter类型的自定义事件,父组件创建实例后订阅该事件,和模板中写(itemClick)="func()"的效果完全一致,是框架推荐的实现方式 - 直接获取动态组件的原生DOM元素,通过
addEventListener绑定原生事件,适用不需要修改子组件的场景
如果要继续使用你原有代码中给实例属性赋值处理函数的写法,只需要用箭头函数做一层包装即可,同时解决传参和this指向问题:
// 注意替换为你子组件实际定义的处理函数属性名 item1.instance.click = () => this.contextOpenDocument(event);
这种方式没有内置的销毁机制,需要手动在组件销毁时清空属性引用,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Sondre Ljovshin
相关产品推荐
相关产品推荐

