因為web component是使用custom element技術建構而成。web component內部也能使用addEventListener方法來綁定。但要注意的二件事。
因為web component是用custom element技術建立的,雖然shadow DOM內部和外部的節點是分開的,但Shadow DOM內部節點的事件還是能正常冒泡。
以模組的角度來考慮的話,HTML的事件實在是不夠用。因為普通的節點關注的是"何時觸發"事件,但模組所關注的是"為什麽"觸發事件。比方說組件內部有子節點新增或刪除時,就沒辦法只使用'click'事件來觸發。在這種情況下,custom event技術就能很好的滿足這種需求。
custom event一共分成二部分,生成事件和觸發事件。想要生成一個事件,直接使用CustomEvent物件就能生成一個事件,而觸發事件請使用dispatchEvent這個方法(就像是vue的$emit)。要注意的是,如果要在事件中寫入資料,請使用'detail'這個參數。
HTML
<my-com id="my-com" card-content="ha! you~">
<div id="slot-div">click</div>
</my-com>
Javascript
class MyComponent extends HTMLElement {
root = null
constructor() {
super();
this.render = this.render.bind(this);
this.ClickEvent = this.ClickEvent.bind(this);
this.ClickEvent2 = this.ClickEvent2.bind(this);
this.root = this.attachShadow({mode: 'open'});
this.root.appendChild(this.render())
}
connectedCallback() {
// 綁定事件
this.root.getElementById('card-title').addEventListener('click', this.ClickEvent)
this.root.getElementById('card-slot').addEventListener('click', this.ClickEvent2)
}
disconnectedCallback() {
// 解除事件
this.root.getElementById('card-title').removeEventListener('click', this.ClickEvent)
this.root.getElementById('card-slot').removeEventListener('click', this.ClickEvent2)
}
render() {
const template = document.createElement('template');
template.innerHTML = `
<div>
<h2 id='card-title'>title</h2>
<div id='card-content'>content</div>
<slot id='card-slot'></slot>
</div>
`;
return template.content;
}
ClickEvent() {
console.log('click')
}
ClickEvent2() {
// 使用CustomEvent物件生成事件
const newEvevt = new CustomEvent('clickSlot', {
bubbles: true,
composed: true,
// 如果有要傳資料,請使用'detail'這個屬性
detail: {
name: 'click Me'
}
})
this.dispatchEvent(newEvevt)
}
}
customElements.define('my-com', MyComponent);
const MyNode = document.querySelector('my-com');
MyNode.addEventListener('click', () => console.log('click2'))
// 從webcomponent 收到事件時,要從'e.detail'中取得資料
MyNode.addEventListener('clickSlot', (e) => console.log(e.detail.name)) // click Me