〈ECMAScript 本質部份〉這一系列文件,之所以要作為實驗性質的文件,主要是想試試,如果有機會拋棄一些包袱的話,在瀏覽器上寫 JavaScript 等,應該要做什麼樣的思考與設計,而在這一系列中,拋棄的最大包袱就是 Internet Explorer,如果你想要考量 Internet Explorer 相容性,可以參考〈JavaScript 本質部份〉。
在事件這邊,由於拋棄了 Internet Explorer 事件模型,相對於〈JavaScript 本質部份〉中對應的文件,你會發現事件封裝時簡單多了,可以在一個獨立的 Evt-1.0.0.js 中撰寫事件模組:
// 主要在允許事件處理器以傳回 false 的方式停止預設行為
function addEvtOn(elem, evtType, handler, capture = false) {
elem.addEventListener(evtType, evt => {
let result = handler.call(evt.currentTarget, evt);
if(result === false) {
evt.preventDefault();
}
return result;
}, capture);
}
function removeEvtOn(elem, evtType, handler, capture = false) {
elem.removeEventListener(evtType, handler, capture);
}
export {addEvtOn, removeEvtOn};
capture
預設為 false
是合理的,在過去為了相容於 Internet Explorer 不支援事件捕捉階段,許多程式庫與應用都未曾考量過捕捉階段的作法,當然,如果不考量 Internet Explorer,也可以試著思考捕捉階段可能的應用場合。
原本的 XD-1.0.0.js 現在變成了 XD-1.1.0.js,主要修改為匯入了 Evt-1.0.0.js:
import {addEvtOn, removeEvtOn} from './Evt-1.0.0.js';
然後在 ElemCollection
類別上,新增了 addEvt
與 removeEvt
兩個方法:
class ElemCollection {
...
// 新增事件處理
addEvt(type, handler, capture = false) {
this.elems.forEach(elem => addEvtOn(elem, type, handler, capture));
return this;
}
// 移除事件處理
removeEvt(type, handler, capture = false) {
this.elems.forEach(elem => removeEvtOn(elem, type, handler, capture));
return this;
}
}
其餘程式碼不變。來看看〈封裝 DOM 操作〉中動態新增圖片的範例,現在可以改寫成底下(你的瀏覽器必須支援 ES6 模組):
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
</head>
<body>
<input id="src" type="text"><button id="add">新增圖片</button>
<div id="images"></div>
<script type="module">
import x from './js/XD-1.1.0.js';
let doc = x(document);
doc.elemsById('add').addEvt('click', evt => {
let img = x('img').toElemCollection()
.attr('src', doc.elemsById('src').val())
.addEvt('click', evt => {
let target = evt.target;
target.parentNode.removeChild(target);
});
doc.elemsById('images').append(img);
});
</script>
</body>
</html>
至於接下來的範例,也可以改寫為:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
</head>
<body>
容器一:
<div id="container1">
<img id="image" src="https://openhome.cc/Gossip/images/caterpillar_small.jpg"/>
</div><br>
容器二:
<div id="container2"></div>
<script type="module">
import {elemsById} from './js/XD-1.1.0.js';
let image = elemsById('image');
image.addEvt('click', evt => {
let c1 = elemsById('container1');
let c2 = elemsById('container2');
if(evt.target.parentNode === c1.get()) {
c2.append(image);
} else {
c1.append(image);
}
});
</script>
</body>
</html>
可以在 XD-1.1.0.js 與 Evt-1.0.0.js 分別下載完整的 .js 檔案。