編寫通用事件工具類 `EventUtil` 時,若 `addHandler` 方法僅為空殼,`image.onload` 事件永遠不會被真正綁定,導致 `alert` 不彈出。本文剖析原因並給出跨瀏覽器相容的完整實現。
var EventUtil = {
addHandler: function (element, type, handler) { /* 空實現 */ },
// ... 其他方法
};
var image = document.getElementById("myImage");
EventUtil.addHandler(image, "load", function (event) {
alert(EventUtil.getTarget(event).src); // 永不執行
});
`addHandler` 未呼叫 `element.addEventListener` / `element.attachEvent` / `element['on'+type]`,事件監聽器根本未註冊,圖片載入完成時無回調可執行。
var EventUtil = {
addHandler: function (element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false); // DOM2 級標準
} else if (element.attachEvent) {
element.attachEvent('on' + type, handler); // IE8 及以下
} else {
element['on' + type] = handler; // DOM0 級備援
}
},
removeHandler: function (element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else if (element.detachEvent) {
element.detachEvent('on' + type, handler);
} else {
element['on' + type] = null;
}
},
getEvent: function (event) {
return event || window.event;
},
getTarget: function (event) {
return event.target || event.srcElement;
},
preventDefault: function (event) {
if (event.preventDefault) event.preventDefault();
else event.returnValue = false;
},
stopPropagation: function (event) {
if (event.stopPropagation) event.stopPropagation();
else event.cancelBubble = true;
}
};
| 情況 | 行為 | 對策 |
|---|---|---|
| 圖片已快取 | 部分瀏覽器不再觸發 onload | 綁定前先檢查 `image.complete`,若 true 手動呼叫 handler |
| src 相同重設 | 不觸發 onload | 先設 `src=""` 再設真實 src,或加時間戳 `src + '?t=' + Date.now()` |
| 跨域圖片 | 載入失敗觸發 onerror | 同步綁定 onerror 處理 |
function loadImage(url, onSuccess, onError) {
var img = new Image();
EventUtil.addHandler(img, 'load', function () {
EventUtil.removeHandler(img, 'load', arguments.callee);
EventUtil.removeHandler(img, 'error', onError);
onSuccess(img);
});
EventUtil.addHandler(img, 'error', function () {
EventUtil.removeHandler(img, 'load', onSuccess);
EventUtil.removeHandler(img, 'error', arguments.callee);
onError(new Error('圖片載入失敗: ' + url));
});
// 快取處理
if (img.complete) {
if (img.naturalWidth !== 0) onSuccess(img);
else onError(new Error('圖片損壞: ' + url));
return;
}
img.src = url;
return img;
}
// 使用
loadImage('https://example.com/logo.png',
function (img) { console.log('載入成功', img.src); },
function (err) { console.error(err); });
補全 `EventUtil.addHandler` 的實際綁定邏輯,並注意圖片快取與跨域情況,即可讓 `image.onload` 可靠觸發。