首页 文章

处理Web组件时的Vanilla JavaScript事件委派

提问于
浏览
1

我当前的项目使用Web组件(Custom Elements和Shadow DOM),这允许我将复杂的逻辑和样式封装在Light DOM之外 .

不幸的是,我现在遇到了障碍,我需要能够随意切换元素,而无需解除绑定和重新绑定事件处理程序的麻烦 .

这听起来像是一个事件委托给我的工作,所以我尝试将事件监听器添加到Light DOM中的父节点,希望事件从Shadow DOM冒出来 .

这似乎违背了Shadow DOM和event.target的封装,它始终是ShadowRoot,而不是孩子 .

在这种情况下,我可以做些什么来允许经典事件委派?下面的代码片段显示了问题 . 我希望能够单击内部DIV并处理单击事件处理程序中的单击,但event.target始终是custom-el

/* jshint esversion: 6 */

customElements.define('custom-el', class extends HTMLElement {

	constructor() {
		super();

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

		const oInnerDiv = document.createElement('div');
		oInnerDiv.classList.add('inner');
    oInnerDiv.style.border = '2px solid blue';
    oInnerDiv.style.padding = '3rem';
		this._shadowRoot.appendChild(oInnerDiv);
	}

});

document.addEventListener('click', oEvent => {
	document.getElementById('result').innerText = oEvent.target.tagName;
}, true);
html {
	box-sizing: border-box;
}

*,
*::before,
*::after {
	box-sizing: inherit;
}

body {
	margin: 0;
	padding: 0;
}

main,
div,
custom-el {
	display: inline-block;
	border: 2px solid black;
	padding: 3rem;
}
<main>
    <custom-el>
</main>
  
<p id="result"></p>

1 回答

  • 2

    如果阴影DOM模式是 open ,则可以在Event.composedPath()方法的帮助下单击内部元素,这将返回交叉节点的数组(首先是innest节点) .

    document.addEventListener('click', oEvent => {
        result.innerText = oEvent.composedPath()[0].tagName;
    }, true);
    

    此方法替换旧的 Event.path 属性 .

    customElements.define('custom-el', class extends HTMLElement {
      constructor() {
        super();
        this._shadowRoot = this.attachShadow({ mode: 'open' });
        const oInnerDiv = document.createElement('div');
        oInnerDiv.classList.add('inner');
        oInnerDiv.style.border = '2px solid blue';
        oInnerDiv.style.padding = '1rem';
    		this._shadowRoot.appendChild(oInnerDiv);      
      }
    });
    
    document.addEventListener('click', oEvent => {
      result.innerText = oEvent.composedPath()[0].tagName;
    });
    
    html {
    	box-sizing: border-box;
    }
    
    *,
    *::before,
    *::after {
    	box-sizing: inherit;
    }
    
    body {
    	margin: 0;
    	padding: 0;
    }
    
    main,
    div,
    custom-el {
    	display: inline-block;
    	border: 2px solid black;
    	padding: 1rem;
    }
    
    <main>
        <custom-el></custom-el>
    </main>
      
    <p id="result"></p>
    

相关问题