DOM 事件详解(一)

声明:转自:http://segmentfault.com/a/1190000000352393

监听事件

在过去,主流浏览器之间对于如何给DOM节点添加事件监听有着很大的不一致性。jQuery这样的前端库为我们封装和抽象了这些差异行为,为事件处理带来了极大的便利。

如今,我们正一步步走向一个标准化的浏览器时代,我们可以更加安全地使用官方规范的接口。为了简单起见,这篇文章将主要介绍在现代浏览器中如何管理事件。如果你在为IE8或者更低版本写JavaScript,我会推荐你使用 polyfill 或者一些框架(如jQuery)来管理事件监听。

在JavaScript中,我们使用如下的方式为元素添加事件监听:

element.addEventListener(<event-name>, <callback>, <use-capture>);
  • event-name(string)
    这是你想监听的事件的名称或类型。它可以是任何的标准DOM事件(click, mousedown, touchstart, transitionEnd,等等),当然也可以是你自己定义的事件名称(我们会在后面介绍自定义事件相关内容)。
  • callback(function)(回调函数)
    这个函数会在事件触发的时候被调用。相应的事件(event)对象,以及事件的数据,会被作为第一个参数传入这个函数。
  • use-capture(boolean)
    这个参数决定了回调函数(callback)是否在“捕获(capture)”阶段被触发。不用担心,我们稍后会对此做详细的解释。
var element = document.getElementById('element');
function callback() {
  alert('Hello');
}

// Add listener
element.addEventListener('click', callback);

移除监听

移除不再使用的事件监听是一个最佳实践(尤其对于长时间运行的Web应用)。我们使用element.removeEventListener()方法来移除事件监听:

element.removeEventListener(<event-name>, <callback>, <use-capture>);

但是removeElementListener有一点需要注意的是:你必须要有这个被绑定的回调函数的引用。简单地调用element.removeEventListener('click');是不能达到想要的效果的。

本质上来讲,如果我们考虑要移除事件监听(我们在长时间运行(long-lived)的应用中需要用到),那么我们就需要保留回调函数的句柄。意思就是说,我们不能使用匿名函数作为回调函数。


  
  
var element = document.getElementById('element'); function callback() { alert('Hello once'); element.removeEventListener('click', callback); } // Add listener element.addEventListener('click', callback);

维护回调函数上下文

一个很容易遇到的问题就是回调函数没有在预想的运行上下文被调用。让我们看一个简单的例子来解释一下:

var element = document.getElementById('element');

var user = {
 firstname: 'Wilson',
 greeting: function(){
   alert('My name is ' + this.firstname);
 }
};

// Attach user.greeting as a callback
element.addEventListener('click', user.greeting);

// alert => 'My name is undefined'

使用匿名函数(Anonymous Functions)

我们希望回调函数中能够正确的输出”My name is Wilson”。事实上,结果确是”My name is undefined”。为了使得 this.firstName 能够返回”Wilson”,user.greeting必须在user对象的上下文环境(context)中被执行(这里的运行上下文指的是.号左边的对象)。

当我们将greeting函数传给addEventListener方法的时候,我们传递的是一个函数的引用;user相应的上下文并没有传递过去。运行的时候,这个回调函数实际上是在element的上下文中被执行了,也就是说,在运行的时候,this指向的是element,而不是user。所以this.firstName是undefined。

有两种方式可以避免这种上下文错误的问题。第一种方法,我们可以在一个匿名函数内部调用user.greeting()方法,从而获得正确的函数执行上下文(user)。

element.addEventListener('click', function() {
  user.greeting();
  // alert => 'My name is Wilson'
});

使用Function.prototype.bind

上一种方式并不是非常好,因为我们不能获得回调函数的句柄以便后面通过.removeEventListener()移除事件监听。另外,这种方式也比较丑陋。。我更喜欢使用.bind()方法(做为ECMAScript 5的标准内建在所有的函数对象中)来生成一个新的函数(被绑定过的函数),这个函数会在指定的上下文中被执行。然后我们将这个被绑定过的函数作为参数传给.addEventListener()的回调函数。

// Overwrite the original function with
// one bound to the context of 'user'
user.greeting = user.greeting.bind(user);

// Attach the bound user.greeting as a callback
button.addEventListener('click', user.greeting);
与此同时,我们获得了回调函数的句柄,从而可以随时从元素上移除相应的事件监听。
```javascrips
button.removeEventListener('click', user.greeting);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值