javascript設計模式(張容銘)學習筆記 – 外觀模式繫結事件

阿曼達蒙發表於2018-09-12

有一個需求要為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();
  }
}

 

相關文章