【问题标题】:Reading data from Angular Elements Web Component in plain JavaScript使用纯 JavaScript 从 Angular Elements Web 组件读取数据
【发布时间】:2020-06-16 04:34:07
【问题描述】:

我正在构建一些WebComponent,我将在不同的库/框架中使用它们,但主要是普通的JavaScript。我正在考虑为此使用Angular Elements,并在几个文档之后构建了一个示例。

它运行良好,内置了所有自然的 Angular 好东西。但是,我正在努力解决的是,从普通的 JavaScript 中读取 Web 组件中的数据,类似于 var result = myComponent.value .

  • 请注意,我正在读取的此数据不是原始数据,也不是单个值。它就像一个包含许多细节的对象,来自一个复杂的WebComponent
  • 我想要readonly property之类的东西
  • 组件的标准Angular 文档始终为此使用@Output()EventEmitter。但由于我将在Angular 世界之外将组件用作WebComponent,因此我不能(也不想)使用这种方法。另外,我不想通知值的每次更改,而只是在需要时读取值

如果我用普通的JavaScript 编写标准的WebComponent,我可以这样做

class MyComponent extends HTMLElement {

    constructor() {
        super();
        this.name = 'Guest';
        this.count = 0;
    }

    // more code...

    // THIS result PROPERTY IS USED TO READ DATA FROM THE WEB COMPONENT
    get result() {
        return { name: this.name, count: this.count }; // <<== to read data
    }

    connectedCallback() {
        this.attachShadow({ mode: 'open' });
        this.shadowRoot.innerHTML = `
            <style>
                styles....
            </style>
            <h1>MyComponent</h1>
            More HTML...
        `;
    }
}

customElements.define('my-component', MyComponent);

// Then I can use <my-component></my-component> in my application HTML
// And in the JavaScript code, I can read data from my-component as

const result = document.querySelector('my-component').result;
// which would be something like { name: 'Guest', count: 0 }

有没有办法在AngularElements 中做到这一点?

【问题讨论】:

  • 可以用纯JSObject.defineProperty吗?
  • @Danny'365CSI'Engelman 你能解释一下Object.defineProperty() 在这个场景中的帮助吗?
  • 从您的 NG 代码中定义一个只有 getter 返回对象的属性,然后行为与上面的 vanilla 代码中的 result getter 完全相同。

标签: javascript angular web-component angular9 angular-elements


【解决方案1】:

好的,所以我现在有 2 个解决方法来处理它!它们更像是 hack,因为 (1) 它们没有按照标准的 Angular 方式完成,并且 (2) 将来可能会随着 Angular 中的实现更改而中断。以下是我可以通过Angular Elements 构建的WebComponent 实现output property 的两种方法

(我正在使用"@angular/core": "~9.1.11" & "@angular/elements": "^9.1.11"

  1. 我的同事指出createCustomElement 仅将输入作为属性公开。见代码here。所以hack是,将属性标记为Input(),然后像普通属性一样从外部读取它!它非常不直观,不遵循任何标准语义。有趣的是,Angular 不会抱怨如果我只有一个 getter 用于装饰有 @Input() 的属性
  2. 一种更好的方法,正如 cmets 中的 Danny '365CSI' Engelman 所指出的,我们可以在原生 HTML 元素上定义一个新属性,使用 Object.defineProperty

请注意,除了选项 (1),更好的方法可能是增强/扩展 Angular 中的逻辑以包含组件类中的其他属性作为元素属性,可能使用新的自定义装饰器,如 @987654337 @。

实现上述两种方法的示例代码

// The component
import { Component, OnInit, ViewEncapsulation, Input, ElementRef } from '@angular/core';

@Component({
    // selector, templateUrl & styleUrls
    encapsulation: ViewEncapsulation.ShadowDom,
})
export class MyComponent implements OnInit {

    constructor(
        private element: ElementRef,
    ) {
        // THIS IS APPROACH 2 => we are defining a 'result2' property on the HTMLElement
        Object.defineProperty(this.element.nativeElement, 'result2', {
            get: () => { return { name: this.name, count: this.count }; },
            enumerable: true,
        });
    }

    public name = 'World';
    public count = 0;

    // More code for component functionalities and state management...

    // Just note that this does NOT work i.e. cannot read it from outside
    public get result0(): ElementMetadata {
        return { name: this.name, count: this.count };
    }
    public set result0(value) { console.log(`result value set to ${value}`); }

    // THIS IS APPROACH 1 => we are marking 'result1' with a getter, as @Input
    @Input()
    public get result1(): ElementMetadata {
        return { name: this.name, count: this.count };
    }
}

// The module (no changes made specifically for this)
export class AppModule {
    constructor(private injector: Injector) { }

    ngDoBootstrap() {
        const custElement = createCustomElement(
            MyComponent,
            { injector: this.injector },
        );
        customElements.define('my-component', custElement);
    }
}

【讨论】:

    猜你喜欢
    • 2015-11-24
    • 1970-01-01
    • 2020-02-28
    • 2022-12-09
    • 2014-07-21
    • 2019-10-14
    • 2020-01-21
    • 2018-10-10
    • 1970-01-01
    相关资源
    最近更新 更多