【问题标题】:Extending native HTML element in Angular 6在 Angular 6 中扩展原生 HTML 元素
【发布时间】:2018-12-04 02:42:53
【问题描述】:

我最近创建了一个在所有浏览器中都运行良好的原生 Web 组件。我将此 Web 组件移动到 Angular 6 应用程序中,并且一切正常。然后我尝试扩展一个原生 HTML 元素,它再次完美运行,除非我将它带入我的 Angular 6 应用程序。

使用来自 Mozilla 的示例,我将尝试说明我的问题。使用以下尝试扩展原生 'p' 元素:

// Create a class for the element
class WordCount extends HTMLParagraphElement {
  constructor() {
    // Always call super first in constructor
    super();

    // count words in element's parent element
    var wcParent = this.parentNode;

    function countWords(node){
      var text = node.innerText || node.textContent
      return text.split(/\s+/g).length;
    }

    var count = 'Words: ' + countWords(wcParent);

    // Create a shadow root
    var shadow = this.attachShadow({mode: 'open'});

    // Create text node and add word count to it
    var text = document.createElement('span');
    text.textContent = count;

    // Append it to the shadow root
    shadow.appendChild(text);


    // Update count when element content changes
    setInterval(function() {
      var count = 'Words: ' + countWords(wcParent);
      text.textContent = count;
    }, 200)

  }
}

// Define the new element
customElements.define('word-count', WordCount, { extends: 'p' });
<p is="word-count">This is some text</p>

通过使用相同的代码并将其放入 Angular 6 应用程序中,组件永远不会运行。我将控制台日志语句放在构造函数和 connectedCallback 方法中,它们永远不会触发。如果我删除 {extends: 'p'} 对象并更改扩展 HTMLParagraphElement 并使其扩展 HTMLElement 成为一个自治的自定义元素,一切都会很好地工作。是我做错了什么还是 Angular 6 不支持自定义的内置元素扩展?

【问题讨论】:

  • 我不知道 Angular 应该如何“支持”自定义的内置插件 - 任何框架/库/第三方代码应该只是一个应该可以工作的 HTML 元素。它对我不起作用,而是表明您的编译/捆绑设置无法正常工作。您是否使用 Typescript 与 Angular 代码一起编译您的 Web 组件?
  • 我的理解是在浏览器级别(在某些浏览器中)支持自定义元素,我只需将其导入到纯 HTML 文件中即可使用此确切代码。我假设将这段代码移动到 Angular 将继续工作,而不需要或任何类型的转译或构建。同样,在我的示例中,如果我创建一个自定义元素并且不尝试扩展一个元素,它可以在 Angular 中使用。第二次我尝试使用 {extends: 'p'} 它停止工作。没想到我需要做任何特定的事情来让它在 Angular 中工作。
  • 你能创建一个 StackBlitz 来展示这个问题吗?
  • 当然 - 这是一个在 Angular 之外工作的示例 stackblitz.com/edit/customized-built-in-element 这是 Angular 中的相同组件不起作用(我还添加了 CUSTOM_ELEMENTS_SCHEMA)stackblitz.com/edit/angular-52fs9p
  • 如果我的回答对您有帮助,请告诉我,因为我也很好奇如何让它发挥作用。

标签: angular6 web-component custom-element


【解决方案1】:

我认为原因是 Angular 在解析组件模板时创建那些定制的内置元素的方式——它可能不知道如何正确地做到这一点。奇怪的是,它认为 is 是一个常规属性,可以在 创建元素之后添加(它不是)。

首先创建元素,然后添加is-attribute 很遗憾不会升级元素。

参见下面的示例:div#d 有一个自定义 input 的无效示例。

customElements.define('my-input', class extends HTMLInputElement {
  connectedCallback() {
    this.value = this.parentNode.id
    this.parentNode.classList.add('connected')
  }
}, {
  extends: 'input'
})

document.addEventListener('DOMContentLoaded', () => {
  b.innerHTML = `<input type="text" is="my-input">`

  let el = document.createElement('input', {
    is: 'my-input'
  })
  el.type = 'text'
  c.appendChild(el)

  // will not work:
  let el2 = document.createElement('input')
  el2.setAttribute('is', 'my-input')
  el2.type = 'text'
  d.appendChild(el2)
})
div {
  border: 3px dotted #999;
  padding: 10px;
}

div::before {
  content: "#"attr(id)" ";
}

.connected {
  background-color: lime;
}
<div id="a"><input type="text" is="my-input"></div>
<div id="b"></div>
<div id="c"></div>
<div id="d"></div>

因此,要让它与 Angular 一起工作,请挂钩到 Angular 组件的生命周期(例如 onInit() 回调)并选择一种工作方式在其中创建您的元素。

【讨论】:

  • 这是完美的,正是我想要的。我非常感谢@connexo 的所有帮助并理解我的漫无边际。这真的很有帮助,如果可以的话,我会投票 10 次。
  • Svelte 有同样的问题。
猜你喜欢
  • 2020-07-29
  • 2019-02-09
  • 1970-01-01
  • 1970-01-01
  • 2019-10-30
  • 2021-12-22
  • 2023-03-05
  • 2018-05-12
相关资源
最近更新 更多