首页 > 解决方案 > 从 StencilJS 到 Angular 的事件发射器

问题描述

我需要监听子组件触发的事件。就我而言,我有一个用模板 v1 制作的“标签”组件,它具有这种结构......

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 类中执行此操作:

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

即使我从@stencil/core 导入@Listen,似乎“clicktab”也是 Angular 看不到的。

有什么提示吗?

标签: javascriptangularstenciljs

解决方案


您应该使用@HostListener('tabClick')而不是@Listen('tabClick').


推荐阅读