document.addEventListener和window.addEventListener有什么区别?

228

在使用PhoneGap时,它有一些默认的JavaScript代码使用document.addEventListener,但我有自己的代码,使用了window.addEventListener

function onBodyLoad(){
  document.addEventListener("deviceready", onDeviceReady, false);
  document.addEventListener("touchmove", preventBehavior, false);
  
  window.addEventListener('shake', shakeEventDidOccur, false);
}

这两者有什么区别,哪一个更好用?


关于 JavaScript,窗口、屏幕和文档有什么区别? - Liam
4个回答

278

documentwindow 是不同的对象,它们有一些不同的事件。在它们上面使用 addEventListener() 监听事件时,实际上监听的是另一个对象上的事件。你应该使用真正拥有你感兴趣的事件的那个对象。

例如,window 对象上有一个 "resize" 事件,而 document 对象上没有。

再比如,"readystatechange" 事件只存在于 document 对象上。

所以基本上,你需要知道哪个对象接收你感兴趣的事件,并在那个特定的对象上使用 .addEventListener()

这里有一个有趣的图表,展示了哪些类型的对象创建哪些类型的事件:https://developer.mozilla.org/en-US/docs/DOM/DOM_event_reference


如果你正在监听一个传播的事件(例如点击事件),那么你可以在 document 对象或者 window 对象上监听该事件。对于传播事件唯一的主要区别在于时间顺序。事件会先到达层次结构中排在最前面的 document 对象,然后才会到达 window 对象,但这种区别通常不重要,所以你可以选择任何一个对象。当处理传播事件时,我发现通常最好选择最靠近事件源的对象来满足你的需求。这意味着当两者都可行时,你应该选择 document 而不是 window。但如果可能的话,我经常会更靠近源并使用 document.body 或甚至文档中更接近的共同父级。


2
我对“冒泡到文档而不是窗口”的事情很好奇。所以我在这里进行了测试-> http://jsfiddle.net/k3qv9/1/。我是否遗漏了什么,或者冒泡实际上发生了? - João Paulo Macedo
1
@JOPLOmacedo - 在你的评论之前,我删除了关于冒泡的部分,因为我不确定哪些事件会冒泡到窗口,哪些不会。我一直看到的协议是在document.body对象或document对象拦截文档范围内的冒泡事件,因此没有理由使用window来处理冒泡事件。无论如何,我的答案的重点是有些事件只存在于window上,有些事件只存在于document上,有些事件两者都有,因此OP应该选择与他们想要处理的事件相对应的对象。 - jfriend00
1
由于“click”事件在文档和窗口中都可用,如果我们在文档和窗口上注册事件,那么文档的单击处理程序会先触发,然后是窗口。因此,从这个角度来看,选择文档更好。http://www.jsfiddle.net/3LcVw/ - coder
如何使用document.body和document添加事件监听器? - SuperUberDuper
1
另一个例子:如果你想通过window为三星电视添加addEventListener("keydown", event),那么它将不起作用。但是如果你使用document做同样的事情,那么它就会生效。这也取决于特定设备如何调用冒泡事件。 - Jakub Kubista
显示剩余9条评论

6

window 绑定指的是由浏览器提供的内置对象,代表了包含 document 的浏览器窗口。调用它的 addEventListener 方法可以注册第二个参数(回调函数),以便在描述其第一个参数的事件发生时调用该函数。

<p>Some paragraph.</p>
<script>
  window.addEventListener("click", () => {
    console.log("Test");
  });
</script>

在选择窗口或文档添加事件监听器之前,请注意以下几点:

  1. windowdocument的大多数事件都是相同的,但一些与loadingunloadingopening/closing相关的事件(如resize),应该在window上设置。
  2. 由于窗口包含文档,因此最好使用文档来处理(如果可以处理)事件,因为事件将首先触发文档。
  3. Internet Explorer不响应在窗口上注册的许多事件,因此需要使用文档来注册事件。

4
在JavaScript中,通常有许多不同的方法来执行相同的操作或查找相同的信息。在您的示例中,您正在寻找一些保证始终存在的元素。windowdocument都符合要求(只有一些区别)。
来自Mozilla开发者网络的内容:

addEventListener()在单个目标上注册单个事件侦听器。事件目标可以是文档中的单个元素、文档本身、窗口或XMLHttpRequest。

因此,只要您能确信您的“目标”始终存在,唯一的区别就是您要监听哪些事件,所以只需使用您喜欢的即可。

9
这不是普遍的真理。不同的事件会在不同的对象上发生。documentwindow并不接收相同的事件。你必须选择接收你感兴趣的事件的对象。有些事件可能会发送到documentwindow,但并非全部。 - jfriend00

0
在我看来,在处理传播的事件时,通常最好选择距离事件源最近并满足您需求的对象。
因此,如果您希望事件发生在元素上,最好使用 window.addEventListener()(假设 window 变量是一个元素),因为在监听事件时最重要的是让代码和事件执行更快:这是唯一重要的事情。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接