Javascript 在web组件中动态添加元素

Javascript 在web组件中动态添加元素,javascript,web-component,native-web-component,Javascript,Web Component,Native Web Component,我想创建一个web组件,其中包含可以添加到的元素列表。 例如,如果我有一个初始模板,如: const template = document.createElement("template"); template.innerHTML = `<input type="text"></input><button>add div</button>`; class MyElement extends HTMLElement { constructor

我想创建一个web组件,其中包含可以添加到的元素列表。 例如,如果我有一个初始模板,如:

const template = document.createElement("template");
template.innerHTML = `<input type="text"></input><button>add div</button>`;

class MyElement extends HTMLElement {
  constructor() {
    super();
    this._shadowRoot = this.attachShadow({ mode: "open" });
    this._shadowRoot.appendChild(template.content.cloneNode(true));
    const button = this._shadowRoot.querySelector("button");
    button.addEventListener("click", this.addDiv);
  }
  addDiv(e) {
    // ...
  }
}
customElements.define("my-element", MyElement);

const template=document.createElement(“模板”);
template.innerHTML=`adddiv`;
类MyElement扩展了HtmleElement{
构造函数(){
超级();
this.\u shadowRoot=this.attachShadow({mode:“open”});
这个.u shadowRoot.appendChild(template.content.cloneNode(true));
const button=this.\u shadowRoot.querySelector(“按钮”);
按钮.addEventListener(“单击”,this.addDiv);
}
addDiv(e){
// ...
}
}
自定义元素。定义(“我的元素”,MyElement);
每次单击按钮时,都会添加一个
,其中包含输入字段中的文本,从而创建如下内容:

<input type="text"></input><button>add div</button>
<div>first text from input added</div>
<div>second text from input added</div>
...
添加div
已添加输入的第一个文本
添加输入的第二个文本
...

在您的情况下,不能对Shadow DOM
shadowRoot
属性使用
insertAjacentHTML()
,因为shadowRoot没有实现元素接口

使用绑定(此) 更好的解决方案是在
shadowRoot
属性上使用
appendChild(
)。但是,您需要在
click
事件回调上添加一个特殊操作

在事件回调中,它确实引用了触发事件的元素,而不是在其中定义回调的对象

为了获取对自定义元素的引用(为了访问影子DOM中的输入元素
shadowRoot
,在
addEventListener()中调用
bind(this)

请参见下面的完整示例:

const template=document.createElement(“模板”);
template.innerHTML=`adddiv`;
类MyElement扩展了HtmleElement{
构造函数(){
超级();
this.\u shadowRoot=this.attachShadow({mode:“open”});
这个.u shadowRoot.appendChild(template.content.cloneNode(true));
const button=this.\u shadowRoot.querySelector(“按钮”);
addEventListener(“单击”,this.addDiv.bind(this));
}
addDiv(e){
var div=document.createElement('div')
div.textContent=此.shadowRoot.querySelector('input').value
this.shadowRoot.appendChild(div)
}
}
自定义元素。定义(“我的元素”,MyElement);

扩展超级竖琴回答:

  • attachShadow()
    默认设置此.shadowRoot
  • attachShadow()
    返回阴影根,因此您可以在其上链接
    .innerHTML
  • appendChild()
    返回附加的DIV,以便可以链接它
  • MyElement类扩展了HtmleElement{
    构造函数(){
    超级();
    this.attachShadow({mode:“open”})
    .innerHTML='adddiv';
    this.shadowRoot.querySelector('button')。onclick=evt=>
    这是树根
    .appendChild(document.createElement(“div”))
    .innerHTML=此.shadowRoot.querySelector(“输入”).value
    }
    }
    自定义元素。定义(“我的元素”,MyElement)

    多亏了Danny的回答,我意识到我不需要创建
    。\u shadowRoot
    ,因此我的问题和Supersharp的答案可以简化为以下内容。我保留了该模板,因为从模板创建web组件是一种很好的做法,因为性能优于使用
    shadowRoot.innerHTML

    const template = document.createElement("template");
    template.innerHTML = `<input type="text"></input><button>add div</button>`;
    
    class MyElement extends HTMLElement {
      constructor() {
        super();
        this.attachShadow({ mode: "open" });
        this.shadowRoot.appendChild(template.content.cloneNode(true));
        const button = this.shadowRoot.querySelector("button");
        button.addEventListener("click", this.addDiv.bind(this));
      }
      addDiv(e) {
        const div = document.createElement("div");
        div.textContent = this.shadowRoot.querySelector("input").value;
        this.shadowRoot.appendChild(div);
      }
    }
    customElements.define("my-element", MyElement);
    
    const template=document.createElement(“模板”);
    template.innerHTML=`adddiv`;
    类MyElement扩展了HtmleElement{
    构造函数(){
    超级();
    this.attachShadow({mode:“open”});
    this.shadowRoot.appendChild(template.content.cloneNode(true));
    const button=this.shadowRoot.querySelector(“按钮”);
    addEventListener(“单击”,this.addDiv.bind(this));
    }
    addDiv(e){
    const div=document.createElement(“div”);
    div.textContent=this.shadowRoot.querySelector(“输入”).value;
    this.shadowRoot.appendChild(div);
    }
    }
    自定义元素。定义(“我的元素”,MyElement);
    
    这可以从网络组件中分离出来。您可能已经尝试过appendChild&cie,有什么问题?关于“模板更好的性能”的文档在哪里?一个。DOM上的innerHTML与一个appendChild没有多大区别(在您上面的代码中,它已经执行了一个(内存中)
    innerHTML
    )。关键点是,您在这两种情况下都要执行一个附加。我不打算执行JSPerf,但我敢说,您上面的代码需要执行比一个.innerHTML更多的CPU操作。并且使您的代码更小,更易于阅读…来自Google的web组件指南:"注意:在上面的代码片段中,我们使用一个模板元素来克隆DOM,而不是设置shadowRoot的innerHTML。这种技术降低了HTML解析成本,因为模板的内容只解析一次,而在shadowRoot上调用innerHTML将解析每个实例的HTML。我们将在下一篇文章中详细讨论模板“是否可以在Web组件中添加HTML元素?”示例:Test

    @Naveen是的,您当然可以在DOM中使用该段落,但
    的内容未显示在浏览器中。请参考图像:[link]()
    const template = document.createElement("template");
    template.innerHTML = `<input type="text"></input><button>add div</button>`;
    
    class MyElement extends HTMLElement {
      constructor() {
        super();
        this.attachShadow({ mode: "open" });
        this.shadowRoot.appendChild(template.content.cloneNode(true));
        const button = this.shadowRoot.querySelector("button");
        button.addEventListener("click", this.addDiv.bind(this));
      }
      addDiv(e) {
        const div = document.createElement("div");
        div.textContent = this.shadowRoot.querySelector("input").value;
        this.shadowRoot.appendChild(div);
      }
    }
    customElements.define("my-element", MyElement);