手写事件模型及事件代理/委托

前端面试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)可以实现当新增子对象时无需再次对其绑定事件,对于动态内容部分尤为合适

缺点是:

事件代理的应用常用应该仅限于上述需求下,如果把所有事件都用代理就可能会出现事件误判,即本不应用触发事件的被绑上了事件。

例子:

   Pencil  Pen  Eraser
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" );
});

单击button元素会冒泡到UL.toolbar元素,使用了e.target来定位到当前点击的button。

Q:手写原生js实现事件代理,并要求兼容浏览器

A:其实就是考核对事件对象e的了解程度,以及在IE下对应的属性名。

查看Demo

// ============ 简单的事件委托
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" );
})

Q:实现事件模型

A:大致实现思路就是创建一个类或是匿名函数,在bind和trigger函数外层作用域创建一个字典对象,用于存储注册的事件及响应函数列表,bind时,如果字典没有则创建一个,key是事件名称,value是数组,里面放着当前注册的响应函数,如果字段中有,那么就直接push到数组即可。trigger时调出来依次触发事件响应函数即可。

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

除非你工作用经常用到原生js写法,否则即使你工作多年,被问到这些问题开始也会很懵逼,所以面试之前,多练习练习手写代码,以至于笔试的时候可以轻松点!

本文由 w3cmark_前端笔记 版权所有,转载时请注明出处。
注明出处格式:w3cmark (http://www.w3cmark.com/2016/439.html)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值