自定義事件
自定義事件主要會(huì)被用于框架、組件設(shè)計(jì)與實(shí)現(xiàn)中。
自定義的事件有許多的創(chuàng)建方式,但實(shí)際的業(yè)務(wù)場(chǎng)景中幾乎不會(huì)被用到,網(wǎng)絡(luò)上的文獻(xiàn)記載其具體的使用場(chǎng)景也相對(duì)較少。
1. 使用 Event 構(gòu)造函數(shù)
使用 Event
構(gòu)造函數(shù)就可以創(chuàng)建一個(gè)自定義事件。
<style>
.btn { border: 1px solid #4caf50; padding: 8px 12px; min-width: 200px; color: #4caf50; background: white; outline: none; }
.btn:active { background: #4caf50; color: white; }
</style>
<div>
<button class="btn">點(diǎn)擊我</button>
</div>
<script>
var afterClick = new Event('afterclick');
var btnEle = document.querySelector('.btn');
btnEle.addEventListener('afterclick', function() {
alert('我是點(diǎn)擊事件執(zhí)行完后做的事情');
});
btnEle.onclick = function() {
alert('我被點(diǎn)擊了');
this.dispatchEvent(afterClick);
};
</script>
使用 new Event
可以創(chuàng)建一個(gè)自定義事件,事件名就是構(gòu)造函數(shù)的第一個(gè)參數(shù) afterclick
,表示點(diǎn)擊事件完成后做的事情。
創(chuàng)建一個(gè)自定義事件后需要給 DOM 元素綁定這個(gè)事件,只有綁定后才能觸發(fā),使用 addEventListener
來(lái)綁定事件。
隨后再給按鈕綁定點(diǎn)擊事件,在事件末尾,即事情做完后,使用 dispatchEvent
觸發(fā)這個(gè)自定義事件。
自定義事件是需要手動(dòng)觸發(fā)的!
Event
構(gòu)造函數(shù)還支持第二個(gè)參數(shù),其接受一個(gè)對(duì)象,可以傳遞三個(gè)屬性,都為布爾值:
bubbles
默認(rèn) false ,表示是否會(huì)冒泡cancelable
默認(rèn) false , 表示事件是否可以被取消composed
默認(rèn) composed, 表示事件是否會(huì)在 Shadow DOM 根節(jié)點(diǎn)之外觸發(fā)。
2. 使用 CustomEvent 構(gòu)造函數(shù)
上面使用 Event
構(gòu)造函數(shù)的例子,將其替換成 CustomEvent
構(gòu)造函數(shù)也是一樣可以執(zhí)行的。
<style>
.btn { border: 1px solid #4caf50; padding: 8px 12px; min-width: 200px; color: #4caf50; background: white; outline: none; }
.btn:active { background: #4caf50; color: white; }
</style>
<div>
<button class="btn">點(diǎn)擊我</button>
</div>
<script>
var afterClick = new CustomEvent('afterclick');
var btnEle = document.querySelector('.btn');
btnEle.addEventListener('afterclick', function() {
alert('我是點(diǎn)擊事件執(zhí)行完后做的事情,我被改成了 CustomEvent');
});
btnEle.onclick = function() {
alert('我被點(diǎn)擊了');
this.dispatchEvent(afterClick);
};
</script>
兩個(gè)例子效果是一樣的。
其主要的區(qū)別在參數(shù)和工作環(huán)境上,CustomEvent 是可以在 WebWorker 中被使用的,而 Event 不行。
CustomEvent 可以在構(gòu)造函數(shù)的第二個(gè)參數(shù)中傳遞 detail
屬性,在事件觸發(fā)時(shí),事件對(duì)象中就會(huì)攜帶這個(gè) detail 屬性。
假設(shè)現(xiàn)在想完成一個(gè)鍵盤的點(diǎn)擊事件,即鍵盤上某個(gè)鍵按下并彈起后做的事情。
<style>
input {width: 200px;padding: 8px;font-size: 16px;outline: none;border: 1px dashed #4caf50;}
input:focus {border: 1px solid #4caf50;}
</style>
<div>
<input type="text">
</div>
<script>
var inputEle = document.querySelector('input');
var onKeyClick = function(e) {
console.log(e);
alert('現(xiàn)在輸入框內(nèi)容是:' + e.detail.value + ',觸發(fā)的鍵是:' + e.detail.keyCode);
};
inputEle.addEventListener('keyup', (e) => {
console.log('鍵盤按鍵彈起了');
var keyClick = new CustomEvent('keyclick', {
detail: {
value: e.target.value,
keyCode: e.keyCode,
},
});
inputEle.addEventListener('keyclick', onKeyClick);
inputEle.dispatchEvent(keyClick);
inputEle.removeEventListener('keyclick', onKeyClick);
});
</script>
這里通過(guò) keyup
事件,在事件處理器的最末尾增加了一個(gè) keyclick
事件。這里并沒有結(jié)合 keydown
來(lái)判斷按鍵的落下和彈起,因?yàn)橐粋€(gè)按鍵要彈起,必定得先落下,所以只需要監(jiān)聽 keyup
。
其實(shí)可以看出這段代碼比較奇怪,真正的業(yè)務(wù)場(chǎng)景并不會(huì)這樣寫,會(huì)選擇直接調(diào)用 onKeyClick
函數(shù)。
<style>
input {width: 200px;padding: 8px;font-size: 16px;outline: none;border: 1px dashed #4caf50;}
input:focus {border: 1px solid #4caf50;}
</style>
<div>
<input type="text">
</div>
<script>
var inputEle = document.querySelector('input');
var onKeyClick = function(value, keyCode) {
alert('現(xiàn)在輸入框內(nèi)容是:' + value + ',觸發(fā)的鍵是:' + keyCode);
};
inputEle.addEventListener('keyup', (e) => {
console.log('鍵盤按鍵彈起了');
onKeyClick(e.target.value, e.keyCode);
});
</script>
這段代碼的執(zhí)行結(jié)果和采用 CustomEvent
的效果是一樣的。
這就是為什么自定義事件更常用于框架或者庫(kù),因?yàn)楸┞妒录袝r(shí)候比單純的提供回調(diào)配置項(xiàng)更好理解和解耦。
3. document.createEvent
使用 document.createEvent 也可以用來(lái)創(chuàng)建自定義事件,但其由于許多配套屬性、方法都已經(jīng)從標(biāo)準(zhǔn)中移除,MDN 也不再建議開發(fā)者使用,所以這里不再深入探討,只做了解。
4. 小結(jié)
自定義事件不常用,主要被應(yīng)用于框架級(jí)別的設(shè)計(jì)上,日常開發(fā)很少有使用場(chǎng)景,許多場(chǎng)景下還會(huì)讓代碼變得冗余復(fù)雜。