如何将选项标签作为分发节点(也称<slot> </slot>)传递给自定义元素

7

我有一个定义如下的Web组件自定义元素。

 <template id="dropdown-template">
        <select>
            <slot></slot>
        </select>
    </template>
    <script>
        class Dropdown extends HTMLElement {
            constructor() {
                super();
                const shadowRoot = this.attachShadow({mode: 'open'});
                let template = document.getElementById('dropdown-template');
                shadowRoot.appendChild(template.content.cloneNode(true));
            }
        }
        customElements.define("drop-down", Dropdown);
    </script>

当我尝试使用它时,我会尝试将带有值的选项标签传递到自定义元素中。
<drop-down>
     <option>one</option>
     <option>two</option>
     <option>three</option>
</drop-down>

这个不起作用。选择元素显示为直接子元素是 <slot> 元素,并且没有渲染选项。使用 <select> 标签无法实现吗?

1个回答

7

这样做是不可能的,因为<option>标签的父元素必须是<select>标签。所以你可以使用Shadow DOM,并且<slot>元素将打破父/子层次结构。

解决方案1:移动元素

一个解决方法是在模板中将轻DOM的内容移入<select>元素中。

class Dropdown extends HTMLElement {
    constructor() {
        super()
        const shadowRoot = this.attachShadow( {mode: 'open'} )
        let template = document.getElementById( 'dropdown-template' )
        shadowRoot.appendChild( template.content.cloneNode(true) )

        const select = shadowRoot.querySelector( 'select' )     
        shadowRoot.addEventListener( 'slotchange', ev => {      
            let node = this.querySelector( 'option' )
            node && select.append( node )
        } )
    }
}
customElements.define("drop-down", Dropdown);
<template id="dropdown-template">
    <select></select>
    <slot></slot>
</template>

<drop-down>
    <option>one</option>
    <option>two</option>
    <option>three</option>
</drop-down>

解决方案2:自定义<select>

另一个可能的解决方案是避免使用Shadow DOM,将下拉列表定义为自定义内置<select>元素。如果您想要自定义布局,这可能不符合您的需求。

<select is="drop-down">
    <option>one</option>
    <option>two</option>
    <option>tree</option>
</select>

另一个解决方案是制作自己的选择/选项系统,而不使用本机选择/选项元素。唉,规范撰写者应该修复这些东西。以某种方式引入新规则? - trusktr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接