Angular 6 在 Angular 元素中使用 ContentChildren/ViewChildren - CustomComponents

Angular 6 using ContentChildren/ViewChildren in AngularElements - CustomComponents

我正在试用新的 AngularElements 功能。 (https://angular.io/guide/elements)

第一次测试是成功的,但是一旦我集成了@ContentChildren,它就停止工作了。这对我来说似乎是合乎逻辑的,因为作为 CustomElement 的新创建的组件无法通过 Angular-Context 获取引用,因为它位于应用程序外部。

我的目标是制作一个最小的 Tab-Wrapper / Tab - 类似组件的结构,因为它们在 angular.io

中使用
<custom-tab-wrapper>
  <anb-tab [title]="'Test'">
    Content
  </anb-tab>
</custom-tab-wrapper>

我还创建了一个 Stackblitz,但这似乎更糟,因为 HMR 多次定义组件导致错误。但这应该让您更好地了解我要实现的目标。

https://stackblitz.com/edit/angular-byvpdz?file=src%2Fapp%2Ftab-wrapper%2Ftab-wrapper.component.ts

主要文件如下:

index.html

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>AngularBlog</title>
  <base href="/">

  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<anb-root></anb-root>
<custom-tab-wrapper>
  <anb-tab [title]="'Test'">
    Content
  </anb-tab>
</custom-tab-wrapper>
</body>
</html>

tab-wrapper.component.ts

import {AfterContentInit, Component, ContentChildren, OnInit, QueryList, ViewEncapsulation} from '@angular/core';
import {TabComponent} from '../tab/tab.component';

   import {AfterContentInit, Component, ContentChildren, OnInit, QueryList, ViewEncapsulation} from '@angular/core';
import {TabComponent} from '../tab/tab.component';

@Component({
  selector: 'anb-tab-wrapper',
  template: `
    <div class="tab-selection-wrapper">
      <h1>Test</h1>
      <div class="tab-selection" (click)="enableTab(tab)" *ngFor="let tab of tabs.toArray()">
        {{tab.title}}
      </div>
    </div>
    <div class="tab-content">
      <ng-content></ng-content>
    </div>
  `,
  encapsulation: ViewEncapsulation.Native
})
export class TabWrapperComponent implements OnInit, AfterContentInit {
  @ContentChildren(TabComponent) tabs: QueryList<TabComponent>;

  constructor() {
    setInterval(() => {
      console.log(this.tabs);
    }, 2000);
  }

  public enableTab(tab: TabComponent) {
    tab.active = true;
    this.tabs.toArray().forEach(tabToCheck => {
      if (tab !== tabToCheck) {
        tabToCheck.active = false;
      }
    });
  }

  ngAfterContentInit(): void {
  }


  ngOnInit() {
  }

}

然后我会有一个选项卡组件。如果我在 angular-root-element 中使用它而不是作为 WebComponent,它会正确呈现。

app.module.ts

import {BrowserModule} from '@angular/platform-browser';
import {Injector, NgModule} from '@angular/core';

import {AppComponent} from './app.component';
import {TabWrapperComponent} from './tab-wrapper/tab-wrapper.component';
import {TabComponent} from './tab/tab.component';
import {createCustomElement} from '@angular/elements';

@NgModule({
  declarations: [
    AppComponent,
    TabWrapperComponent,
    TabComponent
  ],
  entryComponents: [
    TabWrapperComponent,
    TabComponent
  ],
  imports: [
    BrowserModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {

  constructor(private injector: Injector) {
    const tabWrapper = createCustomElement(TabWrapperComponent, {injector: injector});
    customElements.define('custom-tab-wrapper', tabWrapper);
    const tabComponent = createCustomElement(TabComponent, {injector: injector});
    customElements.define('anb-tab', tabComponent);
  }
}

我知道我可以在没有 @ContentChildren 的情况下解决这个问题,但我想在 CustomComponent 中使用这个功能。 所以我的问题是:是否可以使用@ContentChildren / ViewChildren。 如果否,有哪些替代方案?

感谢您的帮助

丹尼尔

Rob Worlmald 回答了我作为 Twitter-Message 发给他的问题。我想与社区分享结果:

他回答了指令和 ContentChild / ContentChildren 是否按以下方式工作的问题:

Nope, they do not - in the current view engine queries are static. In general, because you’re likely to be projecting either vanilla DOM nodes or other (Angular) Custom Elements, you can just use querySelector(All)

这基本上意味着我们可以 select children 在 angular-livecyclce 内或 document.querySelector() 之外。在我个人看来,在 Angular 之外获取它似乎是更简洁的方法,因为不会使用少数额外的行,但仍会在 angular-application 内执行。我会做一些研究。

有关此主题的进一步讨论和可能的解决方法可在此处找到: https://twitter.com/robwormald/status/1005613409486848000

他继续说:

Which you can combine with https://developer.mozilla.org/en-US/docs/Web/Events/slotchange … to approximate the same behaviors

并以未来可能更清洁的解决方案结束:

In ivy (v7 or shortly thereafter) we’ll likely make the query system more flexible and dynamic

将在不久的将来使用 querySelectorAll 更新我的解决方案。