从 StencilJS 到 Angular 的事件发射器
Event emitter from StencilJS to Angular
我需要监听子组件触发的事件。在我的例子中,我有一个在模板 v1 中制作的 "tabs" 组件,它具有这种结构...
abc-tabs.tsx
import { Component, h, Listen, Element, State, Event, Method, EventEmitter } from '@stencil/core';
@Component({
tag: 'abc-tabs'
})
export class AepTabs {
@Element() tabs: HTMLElement;
@State() initIndex: number = 0;
@Event() tabClick: EventEmitter; // <---------- HERE
private tabsElements;
private tabsElementList: Array<any> = [];
private tabTitleElements: any;
componentWillLoad() {
this.createTabsTitles(this.tabs.querySelectorAll('abc-tab'));
}
componentDidLoad() {
this.addTitleEvents();
}
addTitleEvents() {
this.tabTitleElements = this.tabs.getElementsByClassName('tab-title');
[].forEach.call(this.tabTitleElements, (tab, pos) => {
tab.addEventListener('click', () => {
this.tabClick.emit(tab);
this.activeTabs(pos);
});
});
this.activeTabs(this.initIndex);
}
createTabsTitles(tabsList: NodeList) {
this.tabsElements = tabsList;
[].forEach.call(this.tabsElements, tab => {
this.tabsElementList.push(
<div class="tab-title" data-automation={tab.titletab.toString().toLowerCase()}>
<span>{tab.titletab}</span>
</div>
);
});
}
@Method()
activeTabs(index: number) {
this.tabTitleElements = this.tabs.getElementsByClassName('tab-title');
[].forEach.call(this.tabTitleElements, (tab, pos) => {
if (index === pos) {
tab.classList.add('active');
tab.classList.remove('inactive');
} else {
tab.classList.remove('active');
tab.classList.add('inactive');
}
});
[].forEach.call(this.tabsElements, (tab, pos) => {
if (index === pos) {
tab.classList.add('active');
tab.classList.remove('inactive');
} else {
tab.classList.remove('active');
tab.classList.add('inactive');
}
});
}
// HERE --------------------------------------------------------
@Listen('tabClick')
clicktabHandler(event: CustomEvent) {
this.activeTabs(event.detail);
}
// HERE --------------------------------------------------------
render() {
return (
<div>
<nav>{this.tabsElementList}</nav>
<div>
<div>
<slot />
</div>
</div>
</div>
);
}
}
因此,在我的 angular 项目中,我使用了模板组件。
detail.component.html
<abc-tabs>
<abc-tab titletab="My first tab">
<!-- content here -->
</abc-tab>
<abc-tab titletab="My second tab" >
<!-- content here -->
</abc-tab>
</abc-tabs>
一切都很完美,但现在我需要@Listen(在 Angular 中)单击某些选项卡时触发的事件,所以我在 detail.component.ts class:
detail.component.ts
import { Component, OnInit } from '@angular/core';
import { Listen, Watch } from '@stencil/core';
@Component({
selector: 'app-detail',
templateUrl: './detail.component.html'
})
export class DetailComponent implements OnInit {
constructor() {}
ngOnInit() {}
@Listen('tabClick') // <--- ERROR HERE
clicktabHandler(event: CustomEvent) {
console.log('has clicked!!!! ', event.detail);
}
}
但是,它在 detail.component.ts:
中抛出错误
ERROR Error: Uncaught (in promise): TypeError: Object(...) is not a function
TypeError: Object(...) is not a function
似乎'clicktab'是Angular即使我从@stencil/core导入@Listen也看不到的东西。
有什么提示吗?
您应该使用 @HostListener('tabClick')
而不是 @Listen('tabClick')
。
@Listen 是 Stencil 指令,@HostListener 是 Angular 指令。请在相应的项目中使用正确的指令。
我需要监听子组件触发的事件。在我的例子中,我有一个在模板 v1 中制作的 "tabs" 组件,它具有这种结构...
abc-tabs.tsx
import { Component, h, Listen, Element, State, Event, Method, EventEmitter } from '@stencil/core';
@Component({
tag: 'abc-tabs'
})
export class AepTabs {
@Element() tabs: HTMLElement;
@State() initIndex: number = 0;
@Event() tabClick: EventEmitter; // <---------- HERE
private tabsElements;
private tabsElementList: Array<any> = [];
private tabTitleElements: any;
componentWillLoad() {
this.createTabsTitles(this.tabs.querySelectorAll('abc-tab'));
}
componentDidLoad() {
this.addTitleEvents();
}
addTitleEvents() {
this.tabTitleElements = this.tabs.getElementsByClassName('tab-title');
[].forEach.call(this.tabTitleElements, (tab, pos) => {
tab.addEventListener('click', () => {
this.tabClick.emit(tab);
this.activeTabs(pos);
});
});
this.activeTabs(this.initIndex);
}
createTabsTitles(tabsList: NodeList) {
this.tabsElements = tabsList;
[].forEach.call(this.tabsElements, tab => {
this.tabsElementList.push(
<div class="tab-title" data-automation={tab.titletab.toString().toLowerCase()}>
<span>{tab.titletab}</span>
</div>
);
});
}
@Method()
activeTabs(index: number) {
this.tabTitleElements = this.tabs.getElementsByClassName('tab-title');
[].forEach.call(this.tabTitleElements, (tab, pos) => {
if (index === pos) {
tab.classList.add('active');
tab.classList.remove('inactive');
} else {
tab.classList.remove('active');
tab.classList.add('inactive');
}
});
[].forEach.call(this.tabsElements, (tab, pos) => {
if (index === pos) {
tab.classList.add('active');
tab.classList.remove('inactive');
} else {
tab.classList.remove('active');
tab.classList.add('inactive');
}
});
}
// HERE --------------------------------------------------------
@Listen('tabClick')
clicktabHandler(event: CustomEvent) {
this.activeTabs(event.detail);
}
// HERE --------------------------------------------------------
render() {
return (
<div>
<nav>{this.tabsElementList}</nav>
<div>
<div>
<slot />
</div>
</div>
</div>
);
}
}
因此,在我的 angular 项目中,我使用了模板组件。
detail.component.html
<abc-tabs>
<abc-tab titletab="My first tab">
<!-- content here -->
</abc-tab>
<abc-tab titletab="My second tab" >
<!-- content here -->
</abc-tab>
</abc-tabs>
一切都很完美,但现在我需要@Listen(在 Angular 中)单击某些选项卡时触发的事件,所以我在 detail.component.ts class:
detail.component.ts
import { Component, OnInit } from '@angular/core';
import { Listen, Watch } from '@stencil/core';
@Component({
selector: 'app-detail',
templateUrl: './detail.component.html'
})
export class DetailComponent implements OnInit {
constructor() {}
ngOnInit() {}
@Listen('tabClick') // <--- ERROR HERE
clicktabHandler(event: CustomEvent) {
console.log('has clicked!!!! ', event.detail);
}
}
但是,它在 detail.component.ts:
中抛出错误ERROR Error: Uncaught (in promise): TypeError: Object(...) is not a function
TypeError: Object(...) is not a function
似乎'clicktab'是Angular即使我从@stencil/core导入@Listen也看不到的东西。
有什么提示吗?
您应该使用 @HostListener('tabClick')
而不是 @Listen('tabClick')
。
@Listen 是 Stencil 指令,@HostListener 是 Angular 指令。请在相应的项目中使用正确的指令。