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

How to add JavaScript to Custom Elements?

本文关键字:自定义 元素 添加 JavaScript      更新时间:2023-09-26

我有以下代码,它创建了一个自定义元素,用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"时,将从input元素中获取输入并进行处理(在performTask()中),然后将输出放入"#result"中。我的两个问题是:

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

这个之前的堆栈溢出帖子看起来应该回答了我的问题,但所有建议的链接都不再有效,所以我想知道是否有人能给我指正确的方向:)

附言:我宁愿不使用模板,因为并非所有浏览器都支持HTML导入,而且我希望所有自定义元素代码都包含在一个文件中。

原来你可以向影子根本身添加函数,然后你可以在影子根上调用this.parentNode.fn(),直接让孩子访问shadowRoot。。。

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给我的初步见解)

关闭

您可以在Shadow 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 } )

注意:您可以在同一页面中使用不带HTML导入的template。请参阅以下片段:

<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
}