javascript - 扩展的自定义元素在 Angular 2+ 中不起作用
问题描述
我无法让 Angular(2+,不是 AngularJS)与我的扩展自定义元素配合得很好,它的定义如下:
class FancyButton extends HTMLButtonElement {
connectedCallback() {
this.innerText = `I'm a fancy-button!`;
this.style.backgroundColor = 'tomato';
}
}
customElements.define("fancy-button", FancyButton, {
extends: "button"
});
并像这样使用:
<button is="fancy-button">Fancy button here</button>
根据此 Google Developer 资源,该定义完全符合网络标准: https ://developers.google.com/web/fundamentals/web-components/customelements#extend
它在普通网络设置和 React 中运行良好,但 Angular 忽略它并显示一个标准按钮,显然忽略了is="fancy-button"属性。
这是一个堆栈闪电战,展示了这一点。一个花哨的按钮在 Angular 范围 (index.html) 之外并且工作正常。另一个按钮在 Angular 范围内 (app.component.html) 并且不工作。
为什么哦为什么?
解决方案
有两种类型的自定义元素:
自治自定义元素,这些类
extend HTMLElement
自定义的内置元素,它们是扩展特定类型元素的类,例如
extend HTMLButtonElement
.
Angular 不支持自定义的内置元素(下面有更多详细信息)。Safari 也不支持它们(截至 2020 年 9 月:https ://caniuse.com/#search=custom%20elements )。
您的示例是自定义的内置元素。对我有用的解决方法是将任何自定义内置元素重写为围绕内置元素的自治自定义元素。这给了我我想要的封装,它给了我一种自定义内置的方法,它适用于 Angular 和 Safari。
对于上面的示例,翻译为:
class FancyButtonToo extends HTMLElement {
connectedCallback() {
const buttonElement = document.createElement('button');
this.appendChild(buttonElement);
buttonElement.innerText = "Fancy button #2 here!";
buttonElement.style.backgroundColor = 'tomato';
}
}
customElements.define("fancy-button-too", FancyButtonToo);
(该项目还需要schemas: [ CUSTOM_ELEMENT_SCHEMAS]
添加到app.module.ts
)。完整代码在这里:stackblitz,它呈现如下(原始“花式按钮”留作比较):
附加信息
问:我们是否确定 Angular 不支持自定义的内置元素(例如,有一些我们不知道的晦涩配置)?
答:我们确定:https ://html.spec.whatwg.org/multipage/custom-elements.html#custom-elements-autonomous-example 上的规范文档 详细介绍了自治自定义元素和自定义元素之间的区别内置元素。一个重要的区别在于元素的程序化构造:
// Built-in Elements and Autonomous Custom Elements are created like this:
el = createElement(name);
// examples
el = createElement("button"); // normal built-in button
el = createElement("fancy-text"); // a custom element
// Customized Built-in Elements are created like this:
el = createElement(built-in-name, { is: custom-built-in-name });
// example
el = createElement("button", { is: "fancy-button" });
相关的 Angular 模板渲染代码位于 https://github.com/angular/angular/blob/master/packages/platform-b rowser/src/dom/dom_renderer.ts 并且在当前版本的 Angular 中,您将寻找:
class DefaultDomRenderer2 implements Renderer2 {
/* ... */
createElement(name: string, namespace?: string): any {
if (namespace) {
return document.createElementNS(NAMESPACE_URIS[namespace] || namespace, name);
}
return document.createElement(name);
}
/* ... */
}
Angular 渲染器目前没有将第二个参数传递给createElement()
;所需的额外代码。它不能创建自定义内置元素。
推荐阅读
- quickfixj - 有没有办法在代码中获取传入/传出/心跳消息?
- html - 关于如何设计这个 DIV 的任何想法?
- objective-c - 同时处理多个 API
- python - 无法在 PyCharm 中导入张量流
- python-3.x - 将 list 中的列表中的字符串转换为整数
- css - 工作休息在侧选项卡上不起作用
- android - 将 APK 文件从构建位置复制到 gradle 4.4 中的其他位置
- xamarin - 从 .net Web API 检索多个图像并在 Xamarin 表单中填充的最佳方法
- java - 在超类中定义私有子类成员的相同处理
- c# - 当我在 VS 2010 中按 F5 时,是否可以同时在多个浏览器中调试?