如何将 JavaScript 添加到自定义元素?

How to add JavaScript to Custom Elements?

我有以下代码,它创建了一个自定义元素,用 Shadow 封装 DOM:

'use strict'
var proto = Object.create(HTMLElement.prototype);
proto.createdCallback = function() {

    var root = this.createShadowRoot();
    var divEl = document.createElement('div');
    divEl.setAttribute("id", "container");
    divEl.innerHTML =
        "<input id='input' type='text'>"
      + "<br>"
      + "Result: <span id='result'></span>"
      + "<br><button onclick='performTask()'>Run</button>";
    root.appendChild(divEl);

};
document.registerElement('custom-ele', {
    prototype: proto
});

想法是,当单击 'Run' 时,将从输入元素获取输入并进行处理(在 performTask() 中),然后将输出放入“#result”。我的两个问题是:

  1. 如何从 Shadow DOM 中的输入字段中获取值?
  2. 如何将输出放入#result?

This 之前的堆栈溢出 post 看起来可以回答我的问题,但是所有建议的链接都不再有效所以我想知道是否有人可以指出正确的方向 :)

P.S。我不想使用模板,因为 HTML 并非所有浏览器都支持导入,我希望所有自定义元素代码都包含在一个文件中。

事实证明,您可以向影子根本身添加函数,然后您只需调用影子根上的 this.parentNode.fn() 直接子级来访问影子根...

proto.createdCallback = function() {

    let root = this.createShadowRoot();

    root.innerHTML = "<input id='input' type='text'>"
        + "<br>"
        + "Result: <span id='result'></span>"
        + "<br><button onclick='this.parentNode.process()'>Run</button>";

    this.shadowRoot.process = function() {
        let spanEle = this.querySelector('span');
        let inputEle = this.querySelector('input');
        spanEle.textContent = performAlgorithm(inputEle.value.split(','));
    };
};
document.registerElement('custom-ele', { prototype: proto });

(感谢 MarcG 给我的初步见解)

关闭

您可以在阴影 DOM root 上使用方法 querySelector 获取内部元素:

'use strict'
var proto = Object.create( HTMLElement.prototype )
proto.createdCallback = function ()
{
    //HTML ROOT
    var root = this.createShadowRoot()
    root.innerHTML = "<input id='input' type='text'>"
        + "<br>"
        + "Result: <span id='result'></span>"
        + "<br><button>Run</button>"

    //UI
    var buttonEle = root.querySelector( "button" )
    var inputEle = root.querySelector( "input" )
    var spanEle = root.querySelector( "#result" )
    buttonEle.onclick = function ()
    {
        var input = inputEle.value
        // do some processing...
        spanEle.textContent = input
    } 
}
document.registerElement( 'custom-ele', { prototype: proto } )

注意:您可以在同一页面中使用 template 而无需 HTML 导入。请参阅以下代码段:

<html>

<body>
  <custom-ele></custom-ele>

  <template id="custelem">
    <input id='input' type='text'>
    <br>Result:
    <span id='result'></span>
    <br>
    <button>Run</button>
  </template>

  <script>
    var proto = Object.create(HTMLElement.prototype)
    proto.createdCallback = function() {
      //HTML ROOT
      var root = this.createShadowRoot()
      root.innerHTML = custelem.innerHTML

      //UI
      var buttonEle = root.querySelector("button")
      var inputEle = root.querySelector("input")
      var spanEle = root.querySelector("#result")
      buttonEle.onclick = function() {
        var input = inputEle.value
          // do some processing...
        spanEle.textContent = input
      }
    }
    document.registerElement('custom-ele', {
      prototype: proto
    })
  </script>


</body>

</html>

没有关闭

如果您不想使用闭包,您可以在您的自定义元素上声明一个名为 handleEvent 的方法,并添加一个将在其上重定向的事件侦听器:

proto.createdCallback = function ()
{
    //HTML ROOT
    var root = this.createShadowRoot()
    root.innerHTML = custelem.innerHTML

    //EVENT
    var buttonEle = root.querySelector( "button" )
    buttonEle.addEventListener( "click", this )
}

proto.handleEvent = function ( ev )
{
    var inputEle = this.shadowRoot.querySelector( "input" )
    var spanEle = this.shadowRoot.querySelector( "#result" )
    // do some processing...
    spanEle.textContent = inputEle.value
}