JavaScript事件

本文最后更新于:1 年前

事件

JavaScript事件其实是发生在HTML元素上的事件,可以是浏览器行为,也可以是用户行为。

以下是 HTML 事件的实例:

  • HTML 页面完成加载
  • HTML input 的内容被更改时
  • HTML 按钮被点击

在事件触发时,可以用JavaScript 执行一些代码。
HTML 元素中可以添加事件属性,事件通常与函数结合使用,函数不会在事件发生前被执行 (如用户点击按钮)。
HTML的事件有鼠标事件、键盘事件、表单事件、动画事件、拖动事件等等很多种,更多事件可以去这里查看。

下面说一下关于键盘事件的几个问题:

1、执行顺序:keydown-keypress-keyup
2、长按时,会循环执行keydown-keypress
3、有keydown事件,不一定有keyup事件(事件触发过程中,鼠标移走点击别的地方,可能没有keyup事件)
4、keypress事件只能捕获字母、数字、符号键(空格和回车也是),不能捕获功能键,
keydown和keyup基本可以捕获所有功能键(特殊除外)
keypress 区分大小写,keydown和keyup不区分;
keydown和keyup区分主键盘和小键盘,keypress不区分
keypress 只能捕获单键,keydown和keyup可以捕获组合键

确定键盘触发按键的方法:
在触发函数中,传入参数e,代表按键事件;
通过e.keyCode确认按键ASCII码值,进而确定按键;
兼容浏览器系统的写法:

1
2
var evn = e||event; //取到键盘事件
var code = evn.keyCode||evn.which||evn.charCode; //取到按键编码

DOM模型与事件

DOM模型:

在HTML中,每个元素都是一个节点,文档的所有节点组成了DOM 树,DOM又分为几个级别,分别是:

DOM1:DOM1 级由两个模块组成:DOM核心(DOM Core)和DOM HTML。

DOM2:
在DOM1的基础上扩充了:
1、鼠标和用户界面事件、范围、遍历等细分模块
2、通过对象接口增加了对CSS(Cascading Style Sheets,层叠样式表)的支持
3、DOM核心模块也经过扩展开始支持XML 命名空间

DOM3:
1、以统一方式加载和保存文档的方法——在DOM 加载和保存(DOM Load and Save)模块中定义
2、验证文档的方法——在DOM 验证(DOM Validation)模块中定义
3、开始支持XML 1.0 规范

DOM0:首先确定的是在DOM标准中并没有DOM 0级的。我们所说的DOM0事件模型其实就是指的是还没有DOM规范的时候给起 的一个名字,DOM0通过on来绑定事件;而DOM2通过addEventListener来绑定事件,DOM2有捕获、目标、冒泡三个事件阶段。

下面具体说一下DOM0事件模型和DOM2事件模型:

DOM0事件模型

DOM0模型分为两种:

一种是内联模型:直接将函数名作为html标签的某个事件属性的属性值
eg:<button onclick="func()"></button>
缺点:违反了W3C关于html与JS分离的基本原则
另一种是脚本模型:在JS脚本中通过事件属性进行绑定
eg:window.onload = function(){}
局限性:同一节点只能绑定一个同类型事件

DOM2事件模型

1、添加事件绑定:
IE10之前:btn.attachEvent("onclick",函数);
其他浏览器:btn.addEventListener("click",函数,true/false)
  其中,第一个参数为事件
  第三个参数:false为默认,表示事件冒泡;true表示事件捕获
兼容写法:

1
2
3
4
5
if(btn.attachEvent){
  btn.attachEvent();
}else{
  btn.addEventListener();
}

优点:同一节点可以添加多个同类型事件的监听器
2、取消事件绑定:
注:如果要取消事件绑定,那么在绑定事件时,
回调函数必须使用有名函数,而不能使用匿名函数,
因为在取消事件绑定时,需要传入函数名:
.removeEventListener("click",函数名)
.datachEvent("onclick",函数名)

由此可以看出,DOM0和DOM2一个很大区别是DOM0模型的元素绑定多个click最后只执行最后一个click,前面的会被后面的覆盖掉;而DOM2模型的元素绑定可以多个click,不会被覆盖,都会被执行。

JS中的事件流

img

这里有六个套在一起的div,下面解释冒泡和捕获时会用到:

1
2
3
4
5
6
7
8
9
10
11
<div id="div1" style="height: 600px;width: 600px;background-color: aqua;">第一层
<div id="div2" style="height: 500px;width: 500px;background-color: blueviolet;">第二层
<div id="div3" style="height: 400px;width: 400px;background-color: chartreuse;">第三层
<div id="div4" style="height: 300px;width: 300px;background-color: darkorange;">第四层
<div id="div5" style="height: 200px;width: 200px;background-color: firebrick;">第五层
<div id="div6" style="height: 100px;width: 100px;background-color: gray;">第六层</div>
</div>
</div>
</div>
</div>
</div>

1、事件冒泡:
当某DOM元素触发某事件时,会从当前DOM元素开始,逐个触发其祖先元素的同类型事件,直到DOM根节点
DOM0模型均为事件冒泡,IE中使用.attachEvent()添加的事件均为冒泡;
其他浏览器使用.addEventListener()添加的事件当第三个参数为false时,为冒泡

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<script>
var div1 = document.getElementById('div1'),
div2 = document.getElementById('div2'),
div3 = document.getElementById('div3'),
div4 = document.getElementById('div4'),
div5 = document.getElementById('div5'),
div6 = document.getElementById('div6');
div1.addEventListener('click', function () {
console.log("第一层")
}, false);
div2.addEventListener('click', function () {
console.log("第二层")
}, false);
div3.addEventListener('click', function () {
console.log("第三层")
}, false);
div4.addEventListener('click', function () {
console.log("第四层")
}, false);
div5.addEventListener('click', function () {
console.log("第五层")
}, false);
div6.addEventListener('click', function () {
console.log("第六层")
}, false);
</script>

点击中间最小的第六层div时,控制台打印出的结果是这样的:

img

2、事件捕获:
当某DOM元素触发某事件时,会从DOM根节点开始,逐个触发器祖先元素的同类型事件,直到触发到当前元素为止
只有使用.addEventListener()添加事件并设置第三个参数为true时才为捕获

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<script>
var div1 = document.getElementById('div1'),
div2 = document.getElementById('div2'),
div3 = document.getElementById('div3'),
div4 = document.getElementById('div4'),
div5 = document.getElementById('div5'),
div6 = document.getElementById('div6');
div1.addEventListener('click', function () {
console.log("第一层")
}, true);
div2.addEventListener('click', function () {
console.log("第二层")
}, true);
div3.addEventListener('click', function () {
console.log("第三层")
}, true);
div4.addEventListener('click', function () {
console.log("第四层")
}, true);
div5.addEventListener('click', function () {
console.log("第五层")
}, true);
div6.addEventListener('click', function () {
console.log("第六层")
}, true);
</script>

点击中间最小的第六层div时,控制台打印出的结果是这样的:

img

3、阻断事件冒泡\捕获:
阻断捕获只会触发根节点;
IE浏览器中将e.cancleBubble属性设为true
其他浏览器调用e.stopPropagation();方法
兼容写法:

1
2
3
4
5
6
7
8
function myParagraphEventHandler(e) {
  e = e || window.event;
  if (e.stopPropagation) {
  e.stopPropagation(); //IE以外
  } else {
  e.cancelBubble = true; //IE
  }
}

4、取消事件的默认行为:
IE浏览器中:将e.returnValue属性设为false
其他浏览器:调用e.preventDefault();方法
兼容写法:

1
2
3
4
5
6
7
8
9
function eventHandler(e) {
  e = e || window.event;
  // 防止默认行为
  if (e.preventDefault) {
  e.preventDefault(); //IE以外
  } else {
  e.returnValue = false; //IE
  }
}

参考链接:

DOM分级详解

JS中的事件

彻底弄懂JS事件委托的概念和作用

DOM 事件的深入浅出(一)


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!