搜索
首页web前端js教程JavaScript DOM 事件初探的图文代码详细介绍

事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间,比如单击、双击、鼠标悬浮等。

事件流

事件流描述的是从页面中接收事件的顺序,或者说是事件在页面中传播的顺序。

  • IE的事件流叫做事件冒泡(event bubbling):由最具体的元素开始执行事件,然后逐级向上传播到 window 对象。

  • 网景团队提出的事件流叫做事件捕获(event capturing):由最外层的 window 对象开始执行事件,然后逐渐向下传播到最具体的元素。

下面我们做个小实验来说明这两种事件流的不同之处:

// html 文档
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>事件流 实验</title>
</head>
<body>
  <p id="test" style="font-size:3em;">点我点我,我是p</p>
</body>
</html>
// 事件冒泡
var p = document.getElementById("test");
p.addEventListener("click",function(){
  console.log("i am p");
}, false);
document.body.addEventListener("click",function(){
  console.log("i am body");
}, false);
document.documentElement.addEventListener("click",function(){
  console.log("i am html");
}, false);
document.addEventListener("click",function(){
  console.log("i am document");
}, false);
window.addEventListener("click",function(){
  console.log("i am window");
}, false);

event-bubbling.png

点击p,控制端会打印如下:
i am p
i am body
i am html
i am document
i am window
// 事件捕获
var p = document.getElementById("test");
p.addEventListener("click",function(){
  console.log("i am p");
}, true);
document.body.addEventListener("click",function(){
  console.log("i am body");
}, true);
document.documentElement.addEventListener("click",function(){
  console.log("i am html");
}, true);
document.addEventListener("click",function(){
  console.log("i am document");
}, true);
window.addEventListener("click",function(){
  console.log("i am window");
}, true);

event-capturing.png

图片经过二次处理,略丑,请见谅!

点击p,控制端会打印如下:
i am window
i am document
i am html
i am body
i am p

可以看出,事件冒泡和事件捕获是两种完全相反的事件流

平时,一般都是在使用事件冒泡,只在特殊情况下使用事件捕获。

DOM2级事件规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。

// 事件冒泡和事件捕获混合一下
var p = document.getElementById("test");
p.addEventListener("click",function(){
  console.log("i am p");
}, true);
document.body.addEventListener("click",function(){
  console.log("i am body");
}, false);    // 改为在冒泡阶段调用事件处理程序
document.documentElement.addEventListener("click",function(){
  console.log("i am html");
}, true);
document.addEventListener("click",function(){
  console.log("i am document");
}, true);
window.addEventListener("click",function(){
  console.log("i am window");
}, false);    // 改为在冒泡阶段调用事件处理程序

这个图片是直接从书上摘得,自己脑补一下,把 window 对象自行添上去吧!

dom2-event.jpg

点击p,控制端会打印如下:
i am document
i am html
i am p
i am body
i am window

事件处理程序

事件处理程序:指的是响应处理某个事件的函数

HTML 事件处理程序

某个元素支持的每种事件,都可以使用一个与相应事件处理程序同名的 HTML 特性来指定。

// 情况一
<button onclick="alert(&#39;I am button!&#39;);">按钮</button>
// 情况二
<button onclick="show();">按钮</button>
<script>
function show(){
  alert("I am button!");
}
</script>

建议永远不要使用这种方式为元素添加事件,因为这种方法有一个巨大的缺点,就是使得 HTML 与 JavaScript 的代码紧密耦合,不符合网页设计的行为与结构分离。

DOM0 级事件处理程序

每个元素(包括 window 和 document)都有自己的事件处理程序属性,比如 onclick、onmouseup 等。

把上面的代码改写如下:

<button id="test">按钮</button>
var button = document.getElementById("test");
button.onclick = function(){
  // this 对象指向 button 元素
  console.log(this);
  alert("I am button!");
};
/*  删除指定的事件处理程序  */
button.onclick = null;

DOM2 级事件处理程序

DOM2 级事件 定义了两个方法,用来处理指定和删除事件处理程序的操作:addEventListener()和 removeEventListener()

这两个方法都有三个参数,第一个参数是事件名,第二个参数是作为事件处理程序的函数,第三个参数是一个布尔值,默认值是 false,表示在冒泡阶段调用事件处理程序,如果这个值是 true,表示在捕获阶段调用事件处理程序。

继续改写上面的代码:

var button = document.getElementById("test");
function show(){
  // this 对象指向 button 元素
  console.log(this);
  alert("I am button!");
}
// 添加事件处理程序
button.addEventListener("click",show, false);
button.addEventListener("click",function(){
  alert("I am second alert!");
},false);
// 删除事件处理程序
button.removeEventListener("click",show, false); // 删除成功
button.removeEventListener("click",function(){   // 删除失败
  alert("I am second alert!");
},false);

使用 DOM2 级方法添加事件处理程序的主要好处是可以为一个元素添加多个事件处理程序。

如果 addEventListener() 添加的事件处理函数是匿名函数,则无法通过 removeEventListener() 删除这个事件处理程序。

IE 事件处理程序

IE8 以及更早的 IE 版本,只支持事件冒泡,不支持 addEventListener() 和 removeEventListener(),但是它实现了与这两个方法类似的两个方法:attachEvent() 和 detachEvent()。这两个方法只有两个参数,一个事件名称(是 onclick,不是 click),一个事件处理函数。

与 addEventListener() 不同,使用attachEvent() 方法的情况下,事件处理函数会在全局作用域下运行,所以 this 等于 window,这一点需要特别注意。

var button = document.getElementById("test");
button.attachEvent("onclick", function(){
  // this 对象指向了全局作用域,即 window
  console.log(this);
  alert("I am button!");
});
button.attachEvent("onclick",function(){
  alert("I am second alert!");
}); 
// 上面也是为同一个按钮绑定了两个事件处理程序
button.detachEvent("onclick",function(){ // 删除失败
  alert("I am second alert!");
});

除非你想使你的程序兼容至 IE8- 浏览器,否则不要使用这两个函数。

浏览器默认行为

对于一些特定的事件,浏览器有它默认的行为。比如:点击链接会进行跳转到指定的页面、点击鼠标右键会呼出浏览器右键菜单、填写表单时按回车会自动提交到服务器等。

默认的浏览器行为和冒泡行为是独立的,取消事件默认行为是不会取消事件冒泡的,反之亦然。同一个元素的多个事件处理函数也是相互独立的。

<p>
  <a id="test" href="http://baidu.com">点我点我,我是链接</a>
</p>
var link = document.getElementById("test");
// 方法一   event.preventDefault()
link.onclick = function(event){
  console.log("You click!");
  event.preventDefault();
};
// 方法二   return false
link.onclick = function(event){
  console.log("You click!");
  return false;
};

参考:事件-4. 浏览器默认行为-宇卿

事件对象 event

在触发 DOM 上的某个事件时,会产生一个事件对象 event,这个对象中包含着所有与该事件有关的信息。

event 对象只存在于事件处理程序执行期间,一旦执行完毕,立即被销毁。

<p>
  <a id="test" href="http://baidu.com">点我点我,我是链接</a>
</p>
/* 下列 event 对象的属性和方法都是只读的  */
var link = document.getElementById("test");
link.onclick = function(event){
  // 判断当前事件是否会向 DOM 树上层元素冒泡
  console.log(event.bubbles);

  // 判断是否可以取消事件的默认行为
  console.log(event.cancelable);
  // 使用该方法可以取消事件的默认行为(使用前提是 cancelable 属性的值为 true)
  event.preventDefault();
  // 判断是否已经调用了 preventDefault() 方法(DOM3级事件新增)
  console.log(event.defaultPrevented);

  // 指向事件遍历 DOM 时,识别事件的当前目标对象
  console.log(event.currentTarget);
  // 指向触发事件的对象
  console.log(event.target);

  // 表示事件流当前处于哪一个阶段
  // 值为 1 表示在捕获阶段,值为 2 表示处于目标阶段,值为 3 表示在冒泡阶段
  console.log(event.eventPhase);

  // 返回一个字符串, 表示该事件对象的事件类型
  console.log(event.type);

  // 立即停止当前事件在 DOM 层次中的传播,即取消进一步的事件捕获或冒泡
  event.stopPropagation();
};

为了进一步说明 event.stopPropagation() 的运行效果,借用前面的代码,更改如下:

// 事件冒泡和事件捕获混合一下
var p = document.getElementById("test");
p.addEventListener("click",function(){
  console.log("i am p");
}, true);
document.body.addEventListener("click",function(){
  console.log("i am body");
}, false);    // 改为在冒泡阶段调用事件处理程序
document.documentElement.addEventListener("click",function(){
  console.log("i am html");
  event.stopPropagation();    // 立即停止事件在 DOM 中的传播
}, true);
document.addEventListener("click",function(){
  console.log("i am document");
}, true);
window.addEventListener("click",function(){
  console.log("i am window");
}, false);    // 改为在冒泡阶段调用事件处理程序
点击p,控制端会打印如下:
i am document
i am html

看到了吧,后面元素的事件就不会被激发了。

事件类型

UI 事件

UI 事件指的是简单的用户界面事件

load 事件:当页面所有资源(比如图像、css文件、js文件等资源)完全加载完毕后,就会触发 window 上面的 load 事件。

当然,我们也可以单独为某个元素设置 load 事件,比如为一个图片绑定这个事件,就可以检测这个图片是否加载完毕了。

<img id="myImg" src="1.jpg" />
var img = document.getElementById("myImg");
img.onload = function(){
  alert("Image loaded!");
};

scroll 事件:在文档被滚动期间,重复触发该事件。

window.onscroll = function(){
  console.log("Scroll!");
};

焦点事件

焦点事件会在页面元素获得或失去焦点时触发。

注意:默认情况下,只有部分 html 元素能获得鼠标焦点(如 input,a),很大一部分 html 元素是不能获得鼠标焦点的(如 p,img),这些能够获得鼠标焦点的元素就是 focusable 元素。

不过,可以通过为这些默认没有焦点事件的元素添加一个 tabindex 属性,从而使它可以支持焦点事件。

  • document.activeElement:返回当前页面中获得焦点的元素,如果没有某个元素获得焦点,则该属性的值为当前页面中的元素

  • document.hasFocus():判断当前文档或者当前文档的子节点是否获得了焦点

  • HTMLElement.focus():使得指定的元素获得焦点(前提是这个元素是一个可以获得焦点的元素)

  • HTMLElement.blur():移除当前元素获得的焦点

上面是一些 HTML5 中添加的焦点管理 API。下面说焦点事件:

  • focus 事件:在元素获得焦点时触发,这个事件不会冒泡

  • blur 事件:在元素失去焦点时触发,这个事件不会冒泡

  • focusin 事件:在元素获得焦点时触发,与 focus 事件等价,但会冒泡

  • focusout 事件:在元素失去焦点时触发,与 blur 事件等价,但会冒泡

<img id="img" src="1.jpg" tabindex="1" />
var img = document.getElementById("img");
document.body.onscroll = function() {
    img.blur();
};
img.onfocus = function() {
    console.log("Img focused!");
};
img.onblur = function() {
    console.log("Img lose focus!");
};
img.onclick = function() {
    console.log(document.activeElement);
    console.log(document.hasFocus());
};

注意: focusin 和 focusout 事件,所有的 Firefox 版本都不支持,看这里。chrome 和 safari 中只有通过 addEventListener 方式绑定这两个事件才能正常使用,其他方式绑定都不行。

说说focus /focusin /focusout /blur 事件(推荐)
(WHATWG)Focus management APIs

鼠标与滚轮事件

DOM3 级事件中定义了9个鼠标事件。

<body>
 <p id="test">
   <button>按钮</button>
 </p>
</body>
// css
p {
    width: 300px;
    height: 300px;
    margin: 50px auto;
    border: 1px solid #aaa;
  }

mouseover 事件:鼠标指针首次进入一个元素边界之内时触发,会冒泡

mouseout 事件:鼠标指针移出这个元素边界时触发,会冒泡

var test = document.getElementById("test");
test.onmouseover = function(event){
  event.target.style.border = "3px solid #666";
};
test.onmouseout = function(event){
  event.target.style.border = "none";
};

mouseenter 事件:鼠标指针首次移动到元素范围之内时触发,不冒泡

mouseleave 事件:鼠标指针移动到元素范围之外时触发,不冒泡

var test = document.getElementById("test");
test.onmouseenter = function(event){
  event.target.style.border = "10px solid #666";
};
test.onmouseleave = function(event){
  event.target.style.border = "none";
};

mousemove 事件:当鼠标在元素内部移动时重复触发,会冒泡

// 这里写一个鼠标在 body 内移动时,背景颜色随机变化的脚本
document.body.onmousemove = function(){
  var r = Math.floor(Math.random() * 256)
      g = Math.floor(Math.random() * 256)
      b = Math.floor(Math.random() * 256);
  document.body.style.background = "rgb("+r+","+g+","+b+")";
};

mousedown 事件:用户通过按下任意鼠标按钮时触发

mouseup 事件:用户释放鼠标按钮时触发

click 事件:用户单击鼠标左键时或按下回车键时触发

dblclick 事件:用户双击鼠标左键时触发

var body = document.body;
body.onmousedown = function(){
  console.log("Mouse down!");
};
body.onmouseup = function(){
  console.log("Mouse up!");
};
body.onclick = function(){
  console.log("One click!");
};
body.ondblclick = function(){
  console.log("Double click!");
};
// 双击 body,控制端打印:
Mouse down!
Mouse up!
One click!
Mouse down!
Mouse up!
One click!
Double click!

只有在同一个元素上相继触发 mousedown 和 mouseup 事件,才会触发 click 事件,缺一不可。类似地,只有连续触发两次 click 事件,才会触发 dblclick 事件。

获取点击坐标

  • clientX 和 clientY:鼠标指针在视口中的坐标

  • pageX 和 pageY:鼠标指针在页面中的坐标

  • screenX 和 screenY:鼠标指针在屏幕中的坐标

在页面没有滚动的情况下,pageX 和 pageY 的值与 clientX 和 clientY 的值相等。

document.body.onclick = function() {
  console.log("Client: " + "(" + event.clientX + "," + event.clientY + ")");
  console.log("Page: " + "(" + event.pageX + "," + event.pageY + ")");
  console.log("Screen: " + "(" + event.screenX + "," + event.screenY + ")");
};

键盘与文本事件

  • keydown 事件:当用户按下任意键时触发,而且如果按住不放的话,会重复触发此事件

  • keypress 事件:当用户按下任意字符键时触发,而且如果按住不放的话,会重复触发此事件

  • keyup 事件:当用户释放键盘上的按键时触发

在用户按下一个字符键并且立马释放这个按键的过程中,先触发 keydown 事件,再触发 keypress 事件,最后触发 keyup 事件。

window.onkeydown = function() {
  console.log("on key down");
};
window.onkeyup = function() {
  if (event.keyCode === 65) {
    console.log(event.key);
  }
  console.log("one key up");
};
window.onkeypress = function() {
  console.log("one key press");
};

为了知道自己按下的是哪个按键,可以使用 event.which 来获得你按下按键的键码(比如字母 A 的键码为 65)。也可以通过键码属性(event.keyCode)来对特定的按键来进行响应。键码参考表

发生 keypress 事件时,会存在一个 charCode 属性,返回这个按键代表字符的 ASCII 编码。ASCII table

event.which 返回一个 keyCode 或 charCode 值,详情看下面代码

String.fromCharCode() 静态方法可以将 event.which 转化为相应的字符。

// 请自行粘贴复制于浏览器控制端测试
// 分别输入 a 和 A
// A和a 的 ASCII码分别为65,97
window.onkeydown = function(){
  if(event.keyCode === 65){
    console.log("(keydown keyCode)You press &#39;a&#39; or &#39;A&#39;!");
  }
  if(event.charCode === 65){
    console.log("(keydown charCode)You press &#39;A&#39;!");
  }
  console.log("keydown event.which = " + event.which);
  console.log("(keydown:)" + String.fromCharCode(event.which));
};
window.onkeypress = function(){
  if(event.keyCode === 65){
    console.log("(keypress keyCode)You press &#39;A&#39;!");
  }
  if(event.charCode === 65){
    console.log("(keypress charCode)You press &#39;A&#39;,not &#39;a&#39;!");
  }
  console.log("keypress event.which = " + event.which);
  console.log("(keypress:)" + String.fromCharCode(event.which));
};

在 DOM3 级事件中,做了一些变化,不再推荐使用 keyCode、charCode、which 属性,而是出现了两个新属性:key 和 char,用来替代 keyCode 和 charCode 属性。

但是不建议使用 key、char 属性,因为有一部分浏览器对他支持的不是很好。点这里

参考:JavaScript 事件——“事件类型”中“键盘与文本事件”的注意要点

变动事件

变动事件是在 DOM 结构发生变化时触发

在 DOM2 中定义了多个变动事件,但是在 DOM3 中又废除了一些,在这里先简单提一下有这个东西,以后用到再作补充。

HTML5 事件

contextmenu 事件:单击鼠标右键,会触发这个事件并调出页面的上下文菜单。这个事件是鼠标事件的一种,并且支持冒泡。

在上面的例子中,我们演示了利用 contextmenu 事件来设置自定义右键菜单,以及屏蔽右键菜单。

然而,屏蔽右键菜单却难不倒高手,Greasy Fork 上面有一个脚本(网页限制解除),专门来打破对右键菜单有限制的页面。

beforeunload 事件:当浏览器窗口,文档或其资源将要卸载时或者刷新页面时,会触发这个事件【MDN】

下面有几点需要注意一下:

1. 如果处理函数为 Event 对象的 returnValue 属性赋值非空字符串,浏览器会弹出一个对话框,来询问用户是否确定要离开当前页面。没有赋值时,该事件不做任何响应。

2. 从2011年5月25号开始,HTML5规范指出在此事件处理函数中,对于window.alert(), window.confirm(), 和 window.prompt() 的调用会被忽略。

3. 旧版本的浏览器可能会在提示框里显示返回的信息,但是新版本浏览器都默认采用浏览器内设的提示信息。

// 复制粘贴于浏览器控制端,然后关闭页面,会出现提示框
window.addEventListener("beforeunload", function() {
  var message = "你真的要离开吗?";
  event.returnValue = message;
  return message;
}, false);

DOMContentLoaded 事件:在页面文档形成完整的 DOM 树时触发,不理会图像、js文件、css文件等资源是否加载完毕

这个事件可以为 document 或 window 绑定,但实际目标是 document。这个事件会冒泡。

注意:这个事件与 load 事件是不一样的,正常情况下,会早于 load 事件被触发。

感觉篇幅太长了,事件委托移动设备中的事件事件对内存性能的影响等内容将在以后逐渐写出。

以上就是JavaScript DOM 事件初探的图文代码详细介绍的内容,更多相关内容请关注PHP中文网(www.php.cn)!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
超越浏览器:现实世界中的JavaScript超越浏览器:现实世界中的JavaScriptApr 12, 2025 am 12:06 AM

JavaScript在现实世界中的应用包括服务器端编程、移动应用开发和物联网控制:1.通过Node.js实现服务器端编程,适用于高并发请求处理。2.通过ReactNative进行移动应用开发,支持跨平台部署。3.通过Johnny-Five库用于物联网设备控制,适用于硬件交互。

使用Next.js(后端集成)构建多租户SaaS应用程序使用Next.js(后端集成)构建多租户SaaS应用程序Apr 11, 2025 am 08:23 AM

我使用您的日常技术工具构建了功能性的多租户SaaS应用程序(一个Edtech应用程序),您可以做同样的事情。 首先,什么是多租户SaaS应用程序? 多租户SaaS应用程序可让您从唱歌中为多个客户提供服务

如何使用Next.js(前端集成)构建多租户SaaS应用程序如何使用Next.js(前端集成)构建多租户SaaS应用程序Apr 11, 2025 am 08:22 AM

本文展示了与许可证确保的后端的前端集成,并使用Next.js构建功能性Edtech SaaS应用程序。 前端获取用户权限以控制UI的可见性并确保API要求遵守角色库

JavaScript:探索网络语言的多功能性JavaScript:探索网络语言的多功能性Apr 11, 2025 am 12:01 AM

JavaScript是现代Web开发的核心语言,因其多样性和灵活性而广泛应用。1)前端开发:通过DOM操作和现代框架(如React、Vue.js、Angular)构建动态网页和单页面应用。2)服务器端开发:Node.js利用非阻塞I/O模型处理高并发和实时应用。3)移动和桌面应用开发:通过ReactNative和Electron实现跨平台开发,提高开发效率。

JavaScript的演变:当前的趋势和未来前景JavaScript的演变:当前的趋势和未来前景Apr 10, 2025 am 09:33 AM

JavaScript的最新趋势包括TypeScript的崛起、现代框架和库的流行以及WebAssembly的应用。未来前景涵盖更强大的类型系统、服务器端JavaScript的发展、人工智能和机器学习的扩展以及物联网和边缘计算的潜力。

神秘的JavaScript:它的作用以及为什么重要神秘的JavaScript:它的作用以及为什么重要Apr 09, 2025 am 12:07 AM

JavaScript是现代Web开发的基石,它的主要功能包括事件驱动编程、动态内容生成和异步编程。1)事件驱动编程允许网页根据用户操作动态变化。2)动态内容生成使得页面内容可以根据条件调整。3)异步编程确保用户界面不被阻塞。JavaScript广泛应用于网页交互、单页面应用和服务器端开发,极大地提升了用户体验和跨平台开发的灵活性。

Python还是JavaScript更好?Python还是JavaScript更好?Apr 06, 2025 am 12:14 AM

Python更适合数据科学和机器学习,JavaScript更适合前端和全栈开发。 1.Python以简洁语法和丰富库生态着称,适用于数据分析和Web开发。 2.JavaScript是前端开发核心,Node.js支持服务器端编程,适用于全栈开发。

如何安装JavaScript?如何安装JavaScript?Apr 05, 2025 am 12:16 AM

JavaScript不需要安装,因为它已内置于现代浏览器中。你只需文本编辑器和浏览器即可开始使用。1)在浏览器环境中,通过标签嵌入HTML文件中运行。2)在Node.js环境中,下载并安装Node.js后,通过命令行运行JavaScript文件。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
3 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

EditPlus 中文破解版

EditPlus 中文破解版

体积小,语法高亮,不支持代码提示功能

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SecLists

SecLists

SecLists是最终安全测试人员的伙伴。它是一个包含各种类型列表的集合,这些列表在安全评估过程中经常使用,都在一个地方。SecLists通过方便地提供安全测试人员可能需要的所有列表,帮助提高安全测试的效率和生产力。列表类型包括用户名、密码、URL、模糊测试有效载荷、敏感数据模式、Web shell等等。测试人员只需将此存储库拉到新的测试机上,他就可以访问到所需的每种类型的列表。

MinGW - 适用于 Windows 的极简 GNU

MinGW - 适用于 Windows 的极简 GNU

这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

功能强大的PHP集成开发环境