1. 为什么用 shadow dom

使用shadom dom可以让组件与其他组件、组件与dom树进行隔离,实现封装。

如MDN中所写:

每一个 shadow dom 都是一个独立的、隐藏的dom树,附加在了一个元素上。

2. 在custom element中使用shadow dom

接第一篇末的代码

class CommentCard extends HTMLElement{
    constructor(){
        super();

        //将shadow dom附加在自定义元素中
        let shadow = this.attachShadow({mode: 'open'});

        let templateEle = document.getElementById('commentCardTemplate');
        let content = templateEle.content.cloneNode(true);

        content.querySelector('img').src = this.dataset.avatar;
        content.querySelector('.nickname').innerHTML = this.dataset.nickname;

        //向shadow dom中追加元素
        shadow.appendChild(content);
    }
}

Element.attachShadow接受一个配置对象作为参数,它包含一个属性 mode
mode设置为open时,则可以从外部活动并操作shadow dom。
mode设置为closed时,外部将无法访问到shadow dom。

一般来说,我认为没有必要将mode设置为closed。即使在custom elements类定义的内部,我们也无法对shadow dom进行操作。这将影响我们对custom elements的灵活处理,比如样式操作、事件绑定等。这样太不方便了。

3. 操作shadow dom

通过Element.shadowRoot可以获取shadow dom的根结点。
其它操作与常规DOM操作一致。
比如给某个元素添加事件绑定。

class CommentCard extends HTMLElement{
    constructor(){
        super();

        let shadow = this.attachShadow({mode: 'open'});

        let templateEle = document.getElementById('commentCardTemplate');
        let content = templateEle.content.cloneNode(true);

        //向shadow dom中追加元素
        shadow.appendChild(content);

        this.shadowRoot.querySelector('.nickname').addEventListener('click', (e) => {
            this._showBubble(e.target);
        })
    }

    ...
}
03-05 14:06