ShadowDOM v1-输入文字的亮度有所变化

时间:2018-11-19 20:42:45

标签: javascript html shadow-dom

我正在尝试侦听自定义组件中的文本更改

<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title></title>
    <script type="text/javascript" src="component.js"></script>
  </head>
  <body>
    <fancy-p>
      <p>Bar</p>
      <!-- the input should be listened to -->
      <input id="foo" type="text" name="text" placeholder="Hello"></input>
    </fancy-p>
  </body>
</html>

component.js

customElements.define('fancy-p', class extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({mode: 'open'});
  }
  get foo() {
    return "foo"
  }
  connectedCallback() {
    this.shadowRoot.innerHTML = `
      <style>
      p {
        color: red;
      }
      :host {
        background-color: blue;
      }
      </style>
      <div data-foo="bar">
        <slot></slot>
      </div>
    `;

    let input = this.querySelector("input");
    console.log("input is:" + input);
  }
});

我尝试收听文本更改,并在querySelector中使用connectedCallback,但是在Chrome 70.xx中,选择器返回了null

当我设置一个断点时,lightDOM似乎没有被填充(即,插槽),但是我不知道如何向输入中添加事件监听器。

我该怎么做?

2 个答案:

答案 0 :(得分:2)

在您的示例中,<input>被放置在<slot>中,这意味着自定义元素之外的代码拥有<input>标记。

在下面的代码中,您看到我在自定义元素外部使用document.querySelector来获取<input>元素,而不在自定义内部使用this.querySelectorthis.shadowRoot.querySelector元素代码。

customElements.define('fancy-p', class extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({mode: 'open'});
  }
  get foo() {
    return "foo"
  }
  connectedCallback() {
    this.shadowRoot.innerHTML = `
      <style>
      p {
        color: red;
      }
      :host {
        background-color: blue;
      }
      </style>
      <div data-foo="bar">
        <slot></slot>
      </div>
    `;
    let input = this.shadowRoot.querySelector("input");
    console.log('inside input=',input); // input will be null
  }
});


//Since the `<input>` tag is *owned* by the outside DOM you need to get the events from the outside:


let input = document.querySelector("input");
console.log('outside input=', input);
input.addEventListener('input', () => {
  console.log("input is:" + input.value);
});
<fancy-p>
  <p>Bar</p>
  <input id="foo" type="text" name="text" placeholder="Hello"/></fancy-p>

如果要通过shadowDOM访问它,则需要在shadowDOM中定义它:

customElements.define('fancy-p', class extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({mode: 'open'});
  }
  get foo() {
    return "foo"
  }
  connectedCallback() {
    this.shadowRoot.innerHTML = `
      <style>
      p {
        color: red;
      }
      :host {
        background-color: blue;
      }
      </style>
      <div data-foo="bar">
        <slot></slot>
        <input id="foo" type="text" name="text" placeholder="Hello">
      </div>
    `;

    let input = this.shadowRoot.querySelector("input");
    console.log('inside input=',input);
    input.addEventListener('input', () => {
      console.log("input is:" + input.value);
    });
  }
});
<fancy-p>
  <p>Bar</p>
</fancy-p>

答案 1 :(得分:1)

调用connectedCallback()方法时,<input>元素尚未附加到轻型DOM。因此,您当时无法使用this.querySelector('input')来获得它。

这并不是真正的问题:您可以在自定义元素本身上监听{input}事件,因为该事件会冒泡到父元素。

this.addEventListener( 'input', ev => console.log( ev.target, ev.target.value ) )  

请参见运行示例:

customElements.define('fancy-p', class extends HTMLElement {
   constructor() {
      super()
      this.attachShadow({mode: 'open'})
          .innerHTML = `
             <style>
               ::slotted(p) { color: red; }
               :host { display:inline-block; background-color: blue; }
             </style>
             <div data-foo="bar">
               <slot></slot>
            </div>`
      this.addEventListener('input', ev => console.log( '%s value is %s', ev.target, ev.target.value))   
   }
})
<fancy-p>
  <p>Bar</p>
  <input id="foo" type="text" name="text" placeholder="Hello">
</fancy-p>