JS裡關於事件的常被考察的知識點:事件流、事件廣播、原生JS實現事件代理

weixin_34321977發表於2018-07-26

1、JS裡面的事件流

  DOM2級事件模型中規定了事件流的三個階段:捕獲階段、目標階段、冒泡階段,低版本IE(IE8及以下版本)不支援捕獲階段

  捕獲事件流:Netscape提出的事件流,即事件由頁面元素接收,逐級向下,傳播到最具體的元素。

  冒泡事件流:IE提出的事件流,即事件由最具體的元素接收,逐級向上,傳播到頁面。

  關於js事件,這裡有一篇非常詳細的介紹,可以看下:http://www.cnblogs.com/hyaaon/p/4630128.html

2、IE和W3C不同繫結事件解綁事件的方法有什麼區別,引數分別是什麼,以及事件物件e有什麼區別

  繫結事件:

  W3C:target.addEventListener(event, listener, useCapture);

  event —— 事件型別;

  listener —— 事件觸發時執行的函式;

  useCapture —— 指定事件是否在捕獲或冒泡階段執行,為true時事件控制程式碼在捕獲階段執行,為false(預設false)時,事件控制程式碼在冒泡階段執行。

btn.addEventListener('click',function(){
    //do something...
},false)

  對應的事件移除:

removeEventListener(event,function,capture/bubble);

  IE:target.attachEvent(type, listener);

  type - 字串,事件名稱,含“on”,比如“onclick”、“onmouseover”、“onkeydown”等。

  listener —— 實現了 EventListener 介面或者是 JavaScript 中的函式。

btn.attachEvent('onclick',function(){
    //do something...
})

  對應的事件移除:

detachEvent(event,function);

3、事件的委託(代理 Delegated Events)的原理以及優缺點

  委託(代理)事件是那些被繫結到父級元素的事件,但是隻有當滿足一定匹配條件時才會被挪。這是靠事件的冒泡機制來實現的,

  優點是:

  (1)可以大量節省記憶體佔用,減少事件註冊,比如在table上代理所有td的click事件就非常棒 

  (2)可以實現當新增子物件時無需再次對其繫結事件,對於動態內容部分尤為合適

  缺點是:

  事件代理的應用常用應該僅限於上述需求下,如果把所有事件都用代理就可能會出現事件誤判,即本不應用觸發事件的被綁上了事件。

var toolbar = document.querySelector(".toolbar");
toolbar.addEventListener("click", function(e) {
  var button = e.target;
  if(!button.classList.contains("active"))
    button.classList.add("active");
  else
    button.classList.remove("active");
});

4、手寫原生js實現事件代理,並要求相容瀏覽器

// 簡單的事件委託
function delegateEvent(interfaceEle, selector, type, fn) {
    if(interfaceEle.addEventListener){
        interfaceEle.addEventListener(type, eventfn);
    }else{
        interfaceEle.attachEvent("on"+type, eventfn);
    }
      
    function eventfn(e){
        var e = e || window.event;   
        var target = e.target || e.srcElement;
        if (matchSelector(target, selector)) {
            if(fn) {
                fn.call(target, e);
            }
        }
    }
}
/**
 * only support #id, tagName, .className
 * and it's simple single, no combination
 */
function matchSelector(ele, selector) {
    // if use id
    if (selector.charAt(0) === "#") {
        return ele.id === selector.slice(1);
    }
    // if use class
    if (selector.charAt(0) === ".") {
        return (" " + ele.className + " ").indexOf(" " + selector.slice(1) + " ") != -1;
    }
    // if use tagName
    return ele.tagName.toLowerCase() === selector.toLowerCase();
}

//呼叫
var odiv = document.getElementById("oDiv");
delegateEvent(odiv,"a","click",function(){
    alert("1");
})

5、事件如何派發也就是事件廣播(dispatchEvent)

  一般我們在元素上繫結事件後,是靠使用者在這些元素上的滑鼠行為來捕獲或者觸發事件的,或者自帶的瀏覽器行為事件,比如click,mouseover,load等等,有些時候我們需要自定義事件或者在特定的情況下需要觸發這些事件。這個時候我們可以使用IE下fireEvent方法,高階瀏覽器(chrome,firefox等)有dispatchEvent方法

  IE下的例子:

//document上繫結自定義事件ondataavailable
document.attachEvent('ondataavailable', function (event) {
    alert(event.eventType);
});
var obj=document.getElementById("obj");
//obj元素上繫結click事件
obj.attachEvent('onclick', function (event) {
    alert(event.eventType);
});
//呼叫document物件的createEventObject方法得到一個event的物件例項。
var event = document.createEventObject();
event.eventType = 'message';
//觸發document上繫結的自定義事件ondataavailable
document.fireEvent('ondataavailable', event);
//觸發obj元素上繫結click事件
document.getElementById("test").onclick = function () {
    obj.fireEvent('onclick', event);
};

  高階瀏覽器(chrome,firefox等)的例子:

//document上繫結自定義事件ondataavailable
document.addEventListener('ondataavailable', function (event) {
    alert(event.eventType);
}, false);
var obj = document.getElementById("obj");
//obj元素上繫結click事件
obj.addEventListener('click', function (event) {
    alert(event.eventType);
}, false);
//呼叫document物件的 createEvent 方法得到一個event的物件例項。
var event = document.createEvent('HTMLEvents');
// initEvent接受3個引數// 事件型別,是否冒泡,是否阻止瀏覽器的預設行為
event.initEvent("ondataavailable", true, true);
event.eventType = 'message';
//觸發document上繫結的自定義事件ondataavailable
document.dispatchEvent(event);
var event1 = document.createEvent('HTMLEvents');
event1.initEvent("click", true, true);
event1.eventType = 'message';
//觸發obj元素上繫結click事件
document.getElementById("test").onclick = function () {
    obj.dispatchEvent(event1);
};

 

相關文章