【问题标题】:get value from selected option in web component从 Web 组件中的选定选项中获取值
【发布时间】:2020-07-30 04:14:22
【问题描述】:

我正在尝试获取所选选项的值,因此当有人使用我的 Web 组件时,他们可以访问它。我认为问题与影子根有关

__createOptions() {
    const SELECT = this.shadowRoot.querySelector('select');
    SELECT.addEventListener('change', event => {
        this.value= event.target.value;
    });
    this.shadowRoot.addEventListener('slotchange', () => {
        const OPTION = this.querySelector('option');
        if (OPTION) {
            SELECT.append(OPTION);
        }
    });
}

render() {
    return html`
    <div class="selectWrapper">
        <select id="typeDropdown"></select>
    </div>
    <slot></slot>
`;
}

  <wc-select value="">
   <option value="1">Option 1</option>
   <option value"2">Option 2</option>
   <option value="3">Option 3</option>
  </wc-select>

【问题讨论】:

标签: javascript html web-component shadow-dom lit-element


【解决方案1】:

我的评论太快了。

&lt;SLOTs&gt; 不能像“普通”DOM 元素一样定位

(像许多人一样)您正在陷入思考插槽内容的陷阱
移动到 ShadowDOM &lt;slots&gt;

不是

slotted 内容只是 REFLECTED 在 shadowDOM 中,它仍然在 lightDOM 中保持不可见!

您可以通过.querySelector.children[]访问反映内容
...因为它不存在(在 shadowDOM 中).. 它仍然在 lightDOM 中。

出于同样的原因,您在 lightDOM 中设置插槽内容的样式:
Use CSS selectors like :first-child inside shadow dom


将 lightDOM &lt;OPTIONs&gt; 附加到 shadowDOM &lt;SELECT`&gt;

1.您可以将它们从 lightDOM 移动到 shadowDOM:

    let select = this.shadowRoot.querySelector('select');
    let host = this.shadowRoot.getRootNode().host;
    let options = host.querySelectorAll('option');
    select.append(...options);

#1 是最简单的,因为它不需要 shadowDOM 中的任何 &lt;slots&gt;

2。您在 slotchange 事件中走在正确的轨道上
它需要 shadowDOM 模板中的(命名/未命名)&lt;slot&gt;&lt;/slot&gt;
您可以在以下位置找到您的 lightDOM 节点:

请注意,这会得到所有nodeTypes 包括text 节点,因为&lt;my-element&gt; 内部HTML 中有换行符和空格!

    <my-element>
      <option>Grow up</option>
      <option>Learn React</option>
      <option>Learn Lit</option>
      <option>Forget W3C standard Custom Elements API</option>
      <H1 slot=title>My Never Todo List</hH>
    </my-element>

幸运的是&lt;SELECT&gt; 不在乎,所以你可以直接转储assignedNodes..

    this.shadowRoot.addEventListener('slotchange', (evt) => {
      if (!evt.target.name) { // only for unnamed slot
        this.shadowRoot.querySelector('select')
            .append(...evt.target.assignedNodes());
      }
    });

注意!&lt;options&gt;反映到未命名的槽,
&lt;H1 slot=title&gt;反映&lt;slot name=title&gt;

(他们应该将它们命名为 reflections 而不是 slots

点击显示代码片段查看完整代码

customElements.define("my-element", class extends HTMLElement {
  connectedCallback() {
    let template = document.getElementById(this.nodeName);
    this.attachShadow({
      mode: 'open'
    }).append(template.content.cloneNode(true));

    this.shadowRoot.addEventListener('slotchange', (evt) => {
      if (!evt.target.name) { // only for unnamed slot
        let select = this.shadowRoot.querySelector('select');
        select.append(...evt.target.assignedNodes());
      }
    });

  }
})
<template id=MY-ELEMENT>
  <style>
    :host {
      display: block;
    }

    select{
      font-size:1.5em;
    }

  </style>
  <slot name=title></slot>
  <select multiple>
  </select>
  <slot></slot>
</template>

<my-element>
  <option>Grow up</option>
  <option>Learn React</option>
  <option>Learn Lit</option>
  <option>Forget W3C standard Custom Elements API</option>
  <h1 slot=title>My Never Todo List</h1>
</my-element>

具有两个选项的 JSFiddle 游乐场: https://jsfiddle.net/CustomElementsExamples/v2f9zmu5/


更多 SLOT 相关答案可以通过 StackOverflow 搜索找到:Custom Elements SLOTs

【讨论】:

  • 非常感谢您。回答丹尼。我遇到了一个问题,如果有人使用我的 Web 组件“my-element”,他们如何获得select 的值。假设用户无权访问组件的逻辑。所以他们只是打算在他们的项目中导入组件并开始使用它
  • 使用mode:"open",他们始终可以访问document.querySelector('my-element').shadowRoot.querySelector('select')。或添加一个返回指向&lt;select&gt; 的指针的方法。但是恕我直言,您应该将&lt;select&gt; 可以做的所有事情抽象为&lt;my-element&gt; 上的属性(可能还有额外的方法)
  • 使用 自定义内置元素(扩展 HTMLSelectElement)而不是 自治元素(扩展 HTMLElement)会容易得多但是Apple refuses to implement Customized Built-In Elements。因此,如果您不必必须交付给 Safari,您可以扩展 SELECT(在所有其他浏览器中都支持)
猜你喜欢
  • 2019-06-22
  • 2018-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-05
  • 2020-06-03
  • 2015-05-09
相关资源
最近更新 更多