一、事件流
事件流描述了页面接收事件的顺序。DOM完整的事件流包括三个阶段:事件捕获阶段、目标阶段和事件冒泡阶段。
1、事件冒泡(IE事件流)
IE事件流被称为事件冒泡,这是因为事件被定义为从最具体的元素(文档树中最深的节点) 开始触发,在冒泡阶段,事件冒泡,或者事件发生在它的父代,祖父母,直到到达window为止。
<div id="outer">outer
<div id="center">center
<div id="inner">inner</div>
</div>
</div>
var inner = document.getElementById('inner');
var center = document.getElementById('center');
var outer = document.getElementById('outer');
// 当我们只有一个inner点击方法的时候 我们发现想要实现的效果和我们预期的一样
inner.onclick = function () {
console.log('我是inner点击的');
}
// 但是当我们给inner的父元素和祖先元素也添加点击事件时 一点击inner 所有祖先元素的事件都会被触发,这就是事件冒泡现象
center.onclick = function () {
console.log('我是center点击的');
}
outer.onclick = function () {
console.log('我是outer点击的');
}
在点击页面中的id为inner的div元素,click事件会以如下顺序发生
- div#inner
- div#center
- div#outer
- body
- html
- document
2、事件捕获
事件捕获就是由外往内,从事件发生的顶点开始,逐级往下查找,一直到目标元素。
如果前面的例子使用事件捕获,则点击div元素会以下列顺序触发 click 事件:
- document
- html
- body
- div
在事件捕获中,click 事件首先由 document 元素捕获,然后沿 DOM 树依次向下传播,直至到达实际的目标元素div。
3、DOM事件流
事件通过捕获到达目标元素,这个时候就是目标阶段。从目标节点元素将事件上传到根节点的过程就是第三个阶段,冒泡阶段。
在 DOM 事件流中,实际的目标(div元素)在捕获阶段不会接收到事件。这是因为捕获阶段从document 到html再到body就结束了。下一阶段,即会在div元素上触发事件的“到达目标”阶段,通常在事件处理时被认为是冒泡阶段的一部分。然后,冒泡阶段开始,事件反向传播至文档。
二、事件处理程序
事件意味着用户或浏览器执行的某种动作。比如,单击(click)、加载(load)、鼠标悬停(mouseover)。为响应事件而调用的函数被称为事件处理程序(或事件监听器)。事件处理程序的名字以"on"开头,因此 click 事件的处理程序叫作 onclick,而 load 事件的处理程序叫作 onload。有很多方式可以指定事件处理程序。
1、DOM0 事件处理程序
DOM0 级事件分两种,一是直接在标签内直接添加执行语句,二是定义执行函数。
<input type="text" id="test">
<input type="button" value="button" onclick="alert(document.getElementById('test').value)">
<script>
document.getElementById('button').onclick=function(){
alert(document.getElementById('test').value);
}
</script>
2、DOM2 级事件处理程序
DOM2 Events 为事件处理程序的赋值和移除定义了两个方法:
addEventListener()和remove EventListener()。
这两个方法暴露在所有 DOM 节点上,它们接收 3 个参数:
第一个参数:事件名称
第二个参数:执行函数
第三个参数:指定冒泡还是捕获,默认是false,冒泡。
element.addEventListener('click',function(){},false)
三、事件对象
在 DOM 中发生事件时,所有相关信息都会被收集并存储在一个名为 event 的对象中。这个对象包含了一些基本信息,比如导致事件的元素、发生的事件类型,以及可能与特定事件相关的任何其他数据。例如,鼠标操作导致的事件会生成鼠标位置信息,而键盘操作导致的事件会生成与被按下的键有关的信息。所有浏览器都支持这个 event 对象,尽管支持方式不同。
1、阻止默认事件发生
preventDefault()方法
用于阻止特定事件的默认动作。比如,链接的默认行为就是在被单击时导航到 href 属性指定的 URL或是修改表单提交的默认事件。如果想阻止这些行为,可以在 onclick 事件处理程序中取消,如下面的例子所示:
<a href="http://www.baidu.com">跳转</a>
<form action="./1-HTML事件处理程序.html">
<button id="btn">提交按钮</button>
</form>
<script>
var a = document.getElementsByTagName('a')[0];
var btn = document.getElementById('btn');
a.onclick = function (event) {
// alert(1);
// 阻止事件默认行为
event.preventDefault();
}
btn.onclick = function (event) {
// 阻止事件默认行为
event.preventDefault();
}
</script>
四、事件委托
事件委托,又名事件代理。事件委托就是利用事件冒泡,就是把子元素的事件都绑定到父元素上。如果子元素阻止了事件冒泡,那么委托也就没法实现了。
例如,click 事件冒泡到 document。这意味着可以为整个页面指定一个 onclick 事件处理程序,而不用为每个可点击元素分别指定事件处理程序。比如有以下HTML:
<ul id="myLinks">
<li id="li1">Go somewhere</li>
<li id="li2">Do something</li>
<li id="li3">Say hi</li>
</ul>
这里的 HTML 包含 3 个列表项,在被点击时应该执行某个操作。对此,通常的做法是像这样指定 3个事件处理
<script>
var item1 = document.getElementById("li1");
var item2 = document.getElementById("li2");
var item3 = document.getElementById("li3");
item1.addEventListener('click', function () {
this.innerHTML = 'SuZhou';
})
item2.addEventListener('click', function () {
this.innerHTML = 'Coding';
})
item3.addEventListener('click', function () {
this.innerHTML = 'Hi';
})
</script>
如果对页面中所有需要使用 onclick 事件处理程序的元素都如法炮制,结果就会出现大片雷同的只为指定事件处理程序的代码。使用事件委托,只要给所有元素共同的祖先节点添加一个事件处理程序,就可以解决问题。
比如:
<script>
var list = document.getElementById("myLinks");
list.addEventListener("click", function (event) {
var target = event.target;
console.log(target);
switch (target.id) {
case "li1":
target.innerHTML = 'SuZhou';
break;
case "li2":
target.innerHTML = 'Coding';
break;
case "li3":
target.innerHTML = 'Hi';
break;
}
});
</script>
这里只给<ul id="myLinks">
元素添加了一个 onclick 事件处理程序。因为所有列表项都是这个元素的后代,所以它们的事件会向上冒泡,最终都会由这个函数来处理。但事件目标是每个被点击的列表项,只要检查 event 对象的 id 属性就可以确定,然后再执行相应的操作即可。相对于前面不使用事件委托的代码,这里的代码不会导致先期延迟,因为只访问了一个 DOM 元素和添加了一个事件处理程序。结果对用户来说没有区别,但这种方式占用内存更少。所有使用按钮的事件(大多数鼠标事件和键盘事件)都适用于这个解决方案。
五、事件类型
Web 浏览器中可以发生很多种事件。如前所述,所发生事件的类型决定了事件对象中会保存什么信息。DOM3 Events 定义了如下事件类型。
1、用户界面事件(UIEvent)
:涉及与 BOM 交互的通用浏览器事件。
-
load
在 window 上当页面加载完成后触发,在窗套(< frameset >)上当所有窗格(< frame >)
都加载完成后触发,在元素上当图片加载完成后触发,在元素上当相应对象加
载完成后触发。
<script>
window.onload = function () {
console.log('onload');
}
</script>
-
unload
当页面完全卸载后在window上触发,当所有框架都卸载后在框架集上触发,当嵌入的内容卸载完毕后再上触发。
-
select
在文本框(或 textarea)上当用户选择了一个或多个字符时触发。
<input type="text" id="inp">
<script>
var inp = document.getElementById('inp');
inp.onselect = function (event) {
console.log(event);
// 可以通过window.getSelection()获取到选中的部分
console.log(window.getSelection().toString());
}
</script>
<body onresize="myFun()">
<script>
function myFun() {
console.log(window.outerHeight, window.outerWidth);
}
</script>
</body>
<div id="d1" style="width: 100px;height: 100px;border: 1px solid; overflow: auto;">我是div标签我是div标签我是div标签我是div标签我是div标签我是div标签我是div标签我是div标签我是div标签我是div标签我是div标签</div>
<script>
var d1 = document.getElementById('d1');
d1.onscroll = function () {
console.log('onscroll');
}
</script>
2、焦点事件(FocusEvent)
:在元素获得和失去焦点时触发。
<input type="text" id="inp1">
<script>
var inp1 = document.getElementById('inp1');
// 失去焦点触发
inp1.onblur = function () {
console.log('失去焦点');
console.log(this.value);
}
// 获得焦点触发
inp1.onfocus = function () {
console.log('获得焦点');
}
</script>
3、鼠标事件(MouseEvent)和 滚轮事件(WheelEvent)
:使用鼠标在页面上执行某些操作时触发。使用鼠标滚轮(或类似设备)时触发。
-
click
在用户单击鼠标主键(通常是左键)或按键盘回车键时触发。这主要是基于无障碍的考虑,让键盘和鼠标都可以触发 onclick 事件处理程序。
-
dblclick
在用户双击鼠标主键(通常是左键)时触发。这个事件不是在 DOM2 Events 中定义的,但得到了很好的支持,DOM3 Events 将其进行了标准化。
-
mousedown
在用户按下任意鼠标键时触发。这个事件不能通过键盘触发。
-
mouseenter
在用户把鼠标光标从元素外部移到元素内部时触发。这个事件不冒泡,也不会在光标经过后代元素时触发。mouseenter 事件不是在 DOM2 Events 中定义的,而是 DOM3 Events中新增的事件。
-
mouseleave
在用户把鼠标光标从元素内部移到元素外部时触发。这个事件不冒泡,也不会在光标经过后代元素时触发。mouseleave 事件不是在 DOM2 Events 中定义的,而是 DOM3 Events中新增的事件。
-
mousemove
在鼠标光标在元素上移动时反复触发。这个事件不能通过键盘触发。
-
mouseout
在用户把鼠标光标从一个元素移到另一个元素上时触发。移到的元素可以是原始元素的外部元素,也可以是原始元素的子元素。这个事件不能通过键盘触发。
-
mouseover
在用户把鼠标光标从元素外部移到元素内部时触发。这个事件不能通过键盘触发。
-
mouseup
在用户释放鼠标键时触发。这个事件不能通过键盘触发。
-
mousewheel
鼠标滚轮事件
4、键盘事件(KeyboardEvent)和 输入事件(InputEvent)
:使用键盘在页面上执行某些操作时触发。
用户按下键盘上某个键时触发,而且持续按住会重复触发。
用户按下键盘上某个键并产生字符时触发,而且持续按住会重复触发。Esc 键也会触发这个事件。DOM3 Events 废弃了 keypress 事件,而推荐 textInput 事件。
用户释放键盘上某个键时触发。