前端面試題之手寫事件模型及事件代理/委托


原文地址:http://www.w3cmark.com/2016/439.html

 

前端面試js是重頭戲,也是體現面試者的重要方面。jq庫類在前端影響深遠,以至於很多入門者直接用jq代替原生js來開發項目,效率是提升了,但是往往面試官為了考察面試者的基礎,幾乎不可能問你jq里面的某個功能怎么用,而是問你怎么用原生js去實現某個方法或者考察你是否讀個jq的源碼,是否懂得里面真正的原理。

本文來整理一下關於事件的常被考察的知識點

Q:描述下js里面的事件流

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

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

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

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

Q:IE和W3C不同綁定事件解綁事件的方法有什么區別,參數分別是什么,以及事件對象e有什么區別

A:

綁定事件:

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);

  

Q:事件的委托(代理 Delegated Events)的原理以及優缺點

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

優點是:

(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");
});

  


A:
其實就是考核對事件對象e的了解程度,以及在IE下對應的屬性名。單擊button元素會冒泡到UL.toolbar元素,使用了e.target來定位到當前點擊的button。

Q:手寫原生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");
})

 

  

A:大致實現思路就是創建一個類或是匿名函數,在bind和trigger函數外層作用域創建一個字典對象,用於存儲注冊的事件及響應函數列表,bind時,如果字典沒有則創建一個,key是事件名稱,value是數組,里面放着當前注冊的響應函數,如果字段中有,那么就直接push到數組即可。trigger時調出來依次觸發事件響應函數即可。Q:實現事件模型

Q:事件如何派發也就是事件廣播(dispatchEvent)

A:一般我們在元素上綁定事件后,是靠用戶在這些元素上的鼠標行為來捕獲或者觸發事件的,或者自帶的瀏覽器行為事件,比如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);
};

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM