有一個需求要為document物件繫結click事件來是想隱藏提示框的互動功能,於是小白寫了如下程式碼:
document.onclick = function(e) { e.preventDefault(); if(e.target !== document.getElementById(`myinput`)) { hidePageAlert(); } } function hidePageAlert() { //隱藏提示框 }
同事小銘看了看程式碼說:
“首先,你為document 繫結了click事件,但是onclick是DOM0級事件,也就是說這種方式繫結的時間相當於為元素繫結了一個時間方法, 所以如果團隊中的其他人再次通過這種方式為document繫結click事件時,就相當於重複定義了一個方法,會將你定義的click事件方法覆蓋,如下列程式。”
document.onclick= function() { //其他開發人員重新為document繫結時間會覆蓋前面定義的DOM0級click事件 }
“所以你這種方式是很危險的。因此你應該用DOM2級事件處理程式提供的方法addEventListener來實現,然而你知道老版本的IE瀏覽器(低於9)是不支援這個方法的,它支援的是attachEvent,當然如果有不支援DOM2級事件處理程式的瀏覽器,你只能用onclick事件方法來繫結事件。”
“那麼有沒有一個相容所有瀏覽器的方式呢?” 小白追問。
相容模式
// 外觀模式實現 function addEvent(dom, type, fn) { // 對於支援DOM2級事件處理程式addEventListener方法的瀏覽器 if(dom.addEventListener) { dome.addEventListener(type, fn, false); // 對於不支援addEventListener 方法,但是支援attachEvent方法的瀏覽器 }else if(dom.attachEvent) { dom.attachEvent(`on` + type, fn); // 對於不支援addEventListener方法也不支援attachEvent方法,但支援on+`事件名`的瀏覽器 }else{ dom[`on` + type] = fn; } }
“這樣我們以後對於支援addEventListener 或 attachEvent方法的瀏覽器就可以放心的繫結多個事件了, 如下所示。”
var myInput = document.getElementById(`myinput`); addEvent(myInput, `click`, function(){ console.log(`繫結第一個事件`) }) addEvent(myInput, `click`, function(){ console.log(`繫結第二個事件`) })
除此之外
“不過之前寫的程式碼問題不止一個,之前說了,外觀模式可以簡化底層介面複雜性,也可以解決瀏覽器相容性問題。而你之前寫的程式碼除了繫結時間的問題外,另外兩處問題是在其他IE低版本瀏覽器中不相容 e.preventDefault 和 e.target。你也可以通過外觀模式來解決。”
// 獲取事件物件 var getEvent = function(event) { // 標準瀏覽器返回event,IE下window.event return event || window.event; } // 獲取元素 var getTarget = function(event) { var event = getEvent(event); // 標準瀏覽器下event.target, IE下event.srcElement return event.target || event.srcElement; } // 阻止預設行為 var preventDefault = function(event) { var event = getEvent(event); // 標準瀏覽器 if(event.preventDefault) { event.preventDefault(); // IE 瀏覽器 }else { event.returnValue = false; } }
“有了上面的方法,我們就可以用相容的簡單方式來解決上面的問題。”
document.onclick = function(e) { // 阻止預設行為 preventDefault(e); // 獲取事件源目標物件 if(getTarget(e) != document.getElementById(`myinput`)){ hideInputSug(); } }