延迟 "manual" 将元素升级为定制的内置 Web 组件

Late "manual" upgrading of an element towards a customized-built-in web component

我有一个 jQuery 插件(我不想修改)动态创建 div。除此之外,我还有一个 Web 组件 scrollable-div,它是从 HTMLDivElement 扩展而来的自定义内置组件。由于我无法控制 jQuery 插件是如何创建 div 的,因此我需要在创建后以及将其添加到 DOM.[=20= 后对其进行升级]

class myDiv extends HTMLDivElement {
  constructor(...args) {
    const self = super(...args);
    self.addEventListener('click', (e) => {
      e.target.textContent = 'clicked'
    })
    return self;
  }
}

customElements.define('my-div', myDiv, { extends: 'div' });

document.addEventListener('DOMContentLoaded', () => { 
  // this is where I'm trying to turn the div#upgradeMe into a my-div
  upgradeMe.setAttribute('is', 'my-div');
});
<div id="upgradeMe">Click me</div>

简单地添加 is="my-div" 属性显然不能解决问题,div 只是保持常规 HTMLDivElement。如何以编程方式将 DOM 中已有的本机元素升级为自定义的内置 Web 组件?

如果你想支持所有现代浏览器,你不能自定义内置组件,Apple 表示他们永远不会支持 is="" https://github.com/w3c/webcomponents/issues/509#issuecomment-222860736

这是不可能的,因为该元素已经创建为标准 <div> 元素,并且在解析为 可升级(可扩展)时未被识别,因为缺少 is属性。

如果自定义元素已定义,唯一可能的解决方法是用克隆替换现有元素(如@barbsan 的评论中所建议)。

捷径:

  1. 创建一个 <template> 元素
  2. 复制 div 的 outerHTML 到它的 innerHTML 属性
  3. 将模板的 content 替换为 replaceChild()
  4. 的原始元素

class myDiv extends HTMLDivElement {
  constructor(...args) {
    const self = super(...args);
    self.addEventListener('click', (e) => {
      e.target.textContent = 'clicked'
    })
    return self;
  }
}

customElements.define('my-div', myDiv, { extends: 'div' });

document.addEventListener('DOMContentLoaded', () => { 
  // this is where I'm trying to turn the div#upgradeMe into a my-div
  upgradeMe.setAttribute('is', 'my-div');
  var t = document.createElement( 'template' )
  t.innerHTML = upgradeMe.outerHTML
  upgradeMe.parentElement.replaceChild( t.content, upgradeMe )
});
<div id="upgradeMe">Click me</div>

精度

解析元素时,是值受到影响according to the DOM spec:

Elements have an associated namespace, namespace prefix, local name, custom element state, custom element definition, is value. When an element is created, all of these values are initialized.

只有具有有效 is 属性的元素才被识别为可自定义:

An element’s custom element state is one of "undefined", "failed", "uncustomized", or "custom". An element whose custom element state is "uncustomized" or "custom" is said to be defined. An element whose custom element state is "custom" is said to be custom.

因此,如果元素在解析时没有 is 属性,则无法自定义。这就是您不能在之后添加 is 属性的原因。

也在HTML specs:

After a custom element is created, changing the value of the is attribute does not change the element's behavior, as it is saved on the element as its is value.

is 属性仅在元素创建时(在解析时)用于初始化 is 值,如果在元素已创建时更改则无效.在这个意义上 是值 是只读的。