目录
一、浏览器事件
事件 是某事发生的信号。所有的 DOM 节点都生成这样的信号(但事件不仅限于 DOM)。
以下列举出了一些DOM事件
鼠标事件:
click
—— 当鼠标点击一个元素时(触摸屏设备会在点击时生成)。contextmenu
—— 当鼠标右键点击一个元素时。mouseover
/mouseout
—— 当鼠标指针移入/离开一个元素时。mousedown
/mouseup
—— 当在元素上按下/释放鼠标按钮时。mousemove
—— 当鼠标移动时。
键盘事件:
keydown
和keyup
—— 当按下和松开一个按键时。
表单(form)元素事件:
submit
—— 当访问者提交了一个<form>
时。focus
—— 当访问者聚焦于一个元素时,例如聚焦于一个<input>
。
Document 事件:
DOMContentLoaded
—— 当 HTML 的加载和处理均完成,DOM 被完全构建完成时。
CSS 事件:
transitionend
—— 当一个 CSS 动画完成时。
1.事件处理程序
为了对事件作出响应,我们可以分配一个 处理程序(handler)—— 一个在事件发生时运行的函数。处理程序是在发生用户行为(action)时运行 JavaScript 代码的一种方式。
(1).HTML特性
处理程序可以设置在 HTML 中名为 on<event>
的特性(attribute)中。HTML 特性名是大小写不敏感的。
举个例子:
<input value="Click me" onclick="alert('Click!')" type="button">
(2).DOM属性
可以使用 DOM 属性(property)on<event>
来分配处理程序。DOM 属性是大小写敏感的。
举个例子:
<input id="elem" type="button" value="Click me">
<script>
elem.onclick = function() {
alert('Thank you');
};
</script>
因为这里只有一个 onclick
属性,所以我们无法分配更多事件处理程序。
2.addEventListener
上述分配处理程序的方式的根本问题是 —— 我们不能为一个事件分配多个处理程序。
addEventListener 和 removeEventListener
(1).添加处理程序
element.addEventListener(event, handler[, options]);
event
:事件名,例如:"click"
。
handler
:处理程序。
options
:具有以下属性的附加可选对象:
once
:如果为true
,那么会在被触发后自动删除监听器。capture
:事件处理的阶段。由于历史原因,options
也可以是false/true
,它与{capture: false/true}
相同。passive
:如果为true
,那么处理程序将不会调用preventDefault()
。
(2).移除处理程序
element.removeEventListener(event, handler[, options]);
多次调用 addEventListener
允许添加多个处理程序 !!!
3.事件对象
当事件响应函数被触发时,浏览器每次都会将一个事件对象作为实参传递进响应函数,
在事件对象中封装了当前事件相关的一切信息,比如:鼠标的坐标、键盘被哪个按键按下,鼠标滚轮滚动的方向。
event
对象的一些属性:
event.type
:事件类型,这里是 "click"
。
event.currentTarget
:处理事件的元素。这与 this
相同,除非处理程序是一个箭头函数,或者它的 this
被绑定到了其他东西上,之后我们就可以从 event.currentTarget
获取元素了。
event.clientX / event.clientY
:指针事件(pointer event)的指针的窗口相对坐标。
4.对象处理程序handleEvent
可以使用 addEventListener
将一个对象分配为事件处理程序。当事件发生时,就会调用该对象的 handleEvent
方法。
举个例子:
<button id="elem">Click me</button>
<script>
let obj = {
handleEvent(event) {
alert(event.type + " at " + event.currentTarget);
}
};
elem.addEventListener('click', obj);
</script>
二、冒泡和捕获
DOM事件标准描述了事件传播的 3 个阶段:
- 捕获阶段(Capturing phase)—— 事件(从 Window)向下走近元素。
- 目标阶段(Target phase)—— 事件到达目标元素。
- 冒泡阶段(Bubbling phase)—— 事件从元素上开始冒泡。
事件传播过程的示意图如下:
1.冒泡
所谓的冒泡指的就是事件的向上传导,当后代元素上的事件被触发时,其祖先元素的相同事件也会被触发
在开发中大部分冒泡都是有用的,如果不希望发生事件,冒泡可以通过事件对象来取消冒泡
如下图:
点击内部的
<p>
会首先运行 onclick
:
- 在该
<p>
上的。 - 然后是外部
<div>
上的。 - 然后是外部
<form>
上的。 - 以此类推,直到最后的
document
对象。
这个过程被称为“冒泡(bubbling)”,因为事件从内部元素“冒泡”到所有父级,就像在水里的气泡一样。
2.event.target
父元素上的处理程序始终可以获取事件实际发生位置的详细信息。
引发事件的那个嵌套层级最深的元素被称为目标元素,可以通过 event.target
访问。
3.停止冒泡
冒泡事件从目标元素开始向上冒泡。通常,它会一直上升到 <html>
,然后再到 document
对象,有些事件甚至会到达 window
,它们会调用路径上所有的处理程序。
但是任意处理程序都可以决定事件已经被完全处理,并停止冒泡。
用于停止冒泡的方法是 event.stopPropagation()
。
如果一个元素在一个事件上有多个处理程序,即使其中一个停止冒泡,其他处理程序仍会执行。
换句话说,event.stopPropagation()
停止向上移动,但是当前元素上的其他处理程序都会继续运行。
有一个 event.stopImmediatePropagation()
方法,可以用于停止冒泡,并阻止当前元素上的处理程序运行。使用该方法之后,其他处理程序就不会被执行。
4.捕获
捕获阶段很少使用,在事件传播图中,点击 <td>
,事件首先通过祖先链向下到达元素(捕获阶段),然后到达目标(目标阶段),最后上升(冒泡阶段),在途中调用处理程序。
三、事件委托
事件的委托是指将事件统一绑定给元素的共同的祖先元素,这样当后代元素上的事件触发时,会一直冒泡到祖先元素,从而通过祖先元素的响应函数来处理事件。
事件委派是利用了冒泡,通过委派可以减少事件绑定的次数,提高程序的性能
举个例子:
<head>
<meta charset="UTF-8">
<title>Document</title>
<script>
window.onload = function () {
let btn01 = document.getElementById("btn01");
let ul = document.getElementById("ul")
btn01.onclick = function () {
//创建一个li
let li = document.createElement("li")
let a = document.createElement("a")
let text = document.createTextNode("超链接")
a.append(text)
li.append(a)
ul.append(li)
a.href = "#"
a.className = "link"
}
//希望只绑定一次事件,即可应用到多个元素上,即使元素是后来添加的
//可以尝试将其绑定给元素的共同的祖先元素
ul.onclick = function () {
//如果触发的对象是我们期望的元素,则执行,否则不执行
if (event.target.className == "link") {
alert("我是a的单击响应函数")
}
}
}
</script>
</head>
<body>
<button id="btn01">添加超链接</button>
<ul id="ul">
<li><a href="javascript:;" class="link">超链接一</a></li>
<li><a href="javascript:;" class="link">超链接二</a></li>
<li><a href="javascript:;" class="link">超链接三</a></li>
</ul>
</body>
该例中,在ul上绑定事件,触发对象后判断是否是目标对象,是则执行,不是则不执行。