DOM事件机制
HTML DOM 允许 JavaScript 对 HTML 事件作出反应。JavaScript 能够在事件发生时执行,比如当用户点击某个 HTML 元素时。
## 事件是由三部分组成
事件三要素:
1.事件源:事件被触发的对象(按钮对象)
2.事件类型:如何触发?触发什么事件?例如鼠标点击,键盘按下等…
3.事件处理程序:通过一个函数赋值的方式
## 执行事件的步骤
1.获取事件源
2.注册事件(绑定事件)
3.采用函数赋值形式添加事件处理程序
1.事件流
a.事件冒泡(IE事件流)
从最具体的元素开始触发然后一直向上传播至没有那么具体的元素。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
color: white;
font-size: 20px;
}
#outer{
width: 300px;
height: 300px;
background-color: red;
}
#center{
width: 200px;
height: 200px;
background-color: blue;
}
#inner{
width: 100px;
height: 100px;
background-color: green;
}
</style>
</head>
<body>
<div id="outer">outer
<div id="center">center
<div id="inner">inner</div>
</div>
</div>
<script>
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点击的');
}
</script>
</body>
</html>
click事件会以如下顺序发生:
1. div#inner
2. div#center
3. div#outer
4. body
5. html
6. document
阻止事件冒泡
使用event.stopPropagation()
注意:如果点击方法时需要同时传递其他参数和event
onclick(123,event)
b.事件捕获(Netscape事件流)
最不具体的节点应该先受到事件,而最具体的节点应该最后收到事件
目的:为了在事件到达最终目的前拦截事件。
如果前面的例子使用事件捕获,点击div元素会以以下顺序触发click事件:
1. document
2. html
3. body
4. div
c.DOM事件流
DOM2 Events 规范规定事件流分为 3 个阶段:事件捕获、到达目的、事件冒泡
事件捕获最先发生,为提亲拦截事件提供了可能
实际的目标元素接收事件,然后冒泡
注意:所有现代浏览器都支持 DOM 事件流,只有 IE8 及更早版本不支持。
2.事件处理程序
事件:用户或者浏览器执行的某种动作 click loda
a.HTML 事件处理程序
<button οnclick="console.log('Clicked')">点我啊</button>
<button οnclick="console.log("Clicked")">点我啊</button>
包含精确的动作指令
<!-- 需要加() -->
<button οnclick="showMsg()">点我啊</button>
<script>
function showMsg() {
console.log('Hello Wolrd!');
}
</script>
this:相当于事件的目标元素
<button οnclick="this.innerHTML = '我被改变了'">点我啊</button>
b.DOM0 事件处理程序
1.取得要操作的对象的引用
2.把属性赋值为一个函数
<button id='btn'>点我啊</button>
<script>
var btn = document.getElementById('btn');
btn.onclick = function () {
console.log('我被点击了');
}
</script>
使用 this 引用元素本身:
<button id='btn'>点我啊</button>
<script>
var btn = document.getElementById('btn');
btn.onclick = function () {
console.log('我被点击了');
console.log(this.id); //btn
}
</script>
移除处理程序的属性:
btn.οnclick=null;
c.DOM2 事件处理程序
事件处理程序的赋值:
addEventListener()
事件处理程序的移除:
remove EventListenter()
接收三个参数:事件名、事件处理函数、布尔值
布尔值为true:在捕获阶段调用事件处理程序
布尔值为true:在冒泡阶段调用事件处理程序(默认值)
DOM2方式的主要优势是可以为同一个事件添加多个事件处理程序
addEventListener():
<button id='btn'>点我啊</button>
<script>
var btn = document.getElementById("btn");
btn.addEventListener("click", function () {
console.log('我被点击了');
}, false);
btn.addEventListener("click", function () {
console.log(this.id); // btn
});
</script>
remove/EventListener():
使用 addEventListener()添加的匿名函数无法移除
<button id='btn'>点我啊</button>
<script>
var btn = document.getElementById("btn");
btn.addEventListener("click", function () {
console.log('我被点击了');
}, false);
// 移除
btn.removeEventListener("click", function () {
console.log(this.id); //没有效果
})
</script>
传给 removeEventListener()的事件处理函数必须与传给 addEventListener()的是同一个:
<button id='btn'>点我啊</button>
<script>
var btn = document.getElementById("btn");
// 新增一个方法
var handler = function () {
console.log(this.id);
}
btn.addEventListener("click", handler, false);
// 移除
btn.removeEventListener("click", handler, false); // 有效果
</script>
大多数情况下,事件处理程序会被添加到事件流的冒泡阶段,主要原因是跨浏览器兼容性好。
把事件处理程序注册到捕获阶段通常用于在事件到达其指定目标之前拦截事件。如果不需要拦截,则不要使用事件捕获。
3.事件对象
在DOM中发生事件时,相关信息被收集并存储在event对象中
这个对象包含了一些基本信息,比如导致事件的元素、发生的事件类型,以及可能与特定事件相关的任何其他数据。
例如,鼠标操作导致的事件会生成鼠标位置信息。
event 对象只在事件处理程序执行期间存在,一旦执行完毕,就会被销毁。
a.阻止默认事件发生
preventDefault()方法:阻止事件的默认动作
比如链接的默认行为就是被单击时跳转到指定的页面、网页,
想要阻止这些行为,可在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>
4.事件委托
在 JavaScript 中,页面中事件处理程序的数量与页面整体性能直接相关。
原因:每个函数都是对象,都占用内存空间,对象越多,性能越差,
其次为指定事件处理程序所需访问DOM的次数会先期造成整个页面交互的延迟。
处理方法:利用冒泡原理,把事件加到父级上,通过判断事件来源的子集,执行相应操作,
优点:事件委托技术可以避免对每个特定节点添加事件监听器
使用方法:事件委托利用事件冒泡,可以只使用一个事件处理程序来管理一类事件,
例如,例如,click 事件冒泡到 document。这意味着可以为整个页面指定一个 onclick 事件处理程序即可。
<ul id="myLinks">
<li id="li1">Go somewhere</li>
<li id="li2">Do something</li>
<li id="li3">Say hi</li>
</ul>
<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 事件处理程序。
因为所有列表项都是这个元素的后代,所以它们的事件会向上冒泡,最终都会由这个函数来处理。
这种方式占用内存更少。所有使用按钮的事件(大多数鼠标事件和键盘事件)都适用于这个解决方案。
事件委托优点:
1.document 对象随时可用,任何时候都可以给它添加事件处理程序(不用等待 DOMContentLoaded或 load 事件)。这意味着只要页面渲染出可点击的元素,就可以无延迟地起作用。
2.节省花在设置页面事件处理程序上的时间。只指定一个事件处理程序既可以节省 DOM 引用,也可以节省时间。
3.减少整个页面所需的内存,提升整体性能。
5.事件类型
事件发生的类型决定了事件对象中会保存什么信息
**用户界面事件(UIEvent)**:涉及与 BOM 交互的通用浏览器事件。
**焦点事件(FocusEvent)**:在元素获得和失去焦点时触发。
**鼠标事件(MouseEvent)**:使用鼠标在页面上执行某些操作时触发。
**滚轮事件(WheelEvent)**:使用鼠标滚轮(或类似设备)时触发。
**键盘事件(KeyboardEvent)**:使用键盘在页面上执行某些操作时触发。
**输入事件(InputEvent)**:向文档中输入文本时触发。
https://developer.mozilla.org/zh-CN/docs/Web/API/Event
a.用户界面事件-UIEvent
## load
在 window 上当页面加载完成后触发。
<script>
window.onload = function () {
console.log('onload');
}
</script>
## unload
当页面完全卸载后在window上触发,当所有框架都卸载后在框架集上触发,当嵌入的内容卸载完毕后在<object>上触发。
## select
在文本框(<input>或 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>
## resize
在 window 或窗格上当窗口或窗格被缩放时触发。
<body οnresize="myFun()">
<script>
function myFun() {
console.log(window.outerHeight, window.outerWidth);
}
</script>
</body>
## scroll
当用户滚动包含滚动条的元素时在元素上触发。<body>元素包含已加载页面的滚动条。
大多数 HTML 事件与 window 对象和表单控件有关。
<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>
b.焦点事件-FocusEvent
## blur
当元素失去焦点时触发。这个事件不冒泡,所有浏览器都支持。
## focus
当元素获得焦点时触发。这个事件不冒泡,所有浏览器都支持。
<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>
## focusin
当元素获得焦点时触发。这个事件是 focus 的冒泡版。
## focusout
当元素失去焦点时触发。这个事件是 blur 的冒泡版。
c.鼠标事件-MouseEvent和鼠标滚轮事件-WheelEvent
DOM3 Events定义了 9 种鼠标事件:
## click
单击鼠标主键(通常是左键)或者按键盘回车键时触发
## dblclick
用户双击鼠标主键(通常是左键)时触发。
## mousedown
按下任意键盘时触发,这个事件不能通过键盘触发。
## mouseenter
鼠标光标从元素外部移到元素内部时触发。这个事件不冒泡,也不会在光标经过后代元素时触发。
## mouseleave
在用户把鼠标光标从元素内部移到元素外部时触发。这个事件不冒泡,也不会在光标经过后代元素时触发。
## mousemove
在鼠标光标在元素上移动时反复触发。这个事件不能通过键盘触发。
## mouseout
在用户把鼠标光标从一个元素移到另一个元素上时触发。移到的元素可以是原始元素的外部元素,也可以是原始元素的子元素。这个事件不能通过键盘触发。
## mouseover
在用户把鼠标光标从元素外部移到元素内部时触发。这个事件不能通过键盘触发。
## mouseup
在用户释放鼠标键时触发。这个事件不能通过键盘触发。
## mousewheel
鼠标滚轮事件
d.键盘事件-KeyboardEvent与输入事件-InputEvent
键盘事件包含 3 个事件:
- keydown,用户按下键盘上某个键时触发,而且持续按住会重复触发。
- keypress,用户按下键盘上某个键并产生字符时触发,而且持续按住会重复触发。Esc 键也会触发这个事件。DOM3 Events 废弃了 keypress 事件,而推荐 textInput 事件。
- keyup,用户释放键盘上某个键时触发。
输入事件只有一个:textextInput
这个事件是对 keypress 事件的扩展,用于在文本显示给用户之前更方便地截获文本输入。textInput 会在文本被插入到文本框之前触发。
当用户按下键盘上的某个字符键时:
*先触发keydown 事件
*然后触发 keypress 事件
*最后触发 keyup 事件
注意:
*keydown 和 keypress 事件:在文本框出现变化之前触发
*keyup事件:在文本框出现变化之后触发
*如果一个字符键被按住不放:keydown 和 keypress 就会重复触发,直到这个键被释放
非字符键:
*先触发keydown事件
*然后触发keyup事件
注意:如果按住某个非字符键不放,则会重复触发 keydown 事件,直到这个键被释放,此时会触发 keyup 事件。