JavaScript与HTML之间的交互是通过事件实现的。事件就是文档或浏览器窗口中发生的一些特定的交互瞬间。
事件是由三部分组成
事件源
事件类型
事件处理程序
我们也称为事件三要素
1.事件源:事件被触发的对象 -->按钮对象
2.事件类型:如何触发?触发什么事件?例如鼠标点击,键盘按下等…
3.事件处理程序:通过一个函数赋值的方式
执行事件的步骤
1.获取事件源
2.注册事件(绑定事件)
3.采用函数赋值形式添加事件处理程序
常用事件:
-
当用户点击鼠标时
-
当网页加载后
-
当图像加载后
-
当鼠标移至元素上时
-
当输入字段被改变时
-
当 HTML 表单被提交时
-
当用户敲击按键时
一.DOM事件级别
DOM事件分为3个级别:DOM0级事件处理,DOM2级事件处理和DOM3级事件处理。
1.HTML事件处理程序(DOM之前的处理机制)
都是在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>
最大的缺点就是HTML与JS强耦合,当我们一旦需要修改函数名就得修改两个地方。当然其优点就是不需要操作DOM来完成事件的绑定。(耦合:模块间的依赖性,相互联系)
2.DOM0 事件处理程序
DOM 0级的事件处理的步骤:先找到DOM节点,然后把处理函数赋值给该节点对象的事件属性。
在DOM定义方法:
<button id="btn" type="button"></button>
<script>
var btn = document.getElementById('btn');
btn.onclick = function() {
alert('Hello World');
}
// btn.onclick = null; 解绑事件
</script>
DOM0级事件处理程序的缺点在于一个处理程序「事件」无法同时绑定多个处理函数
3.DOM2级事件处理
DOM2级事件在DOM0级事件的基础上弥补了一个处理程序无法同时绑定多个处理函数的缺点,允许给一个处理程序添加多个处理函数。也就是说,使用DOM2事件可以随意添加多个处理函数,移除DOM2事件要用removeEventListener。
DOM2 Events 为事件处理程序的赋值和移除定义了两个方法:addEventListener()和removeEventListener()。
这两个方法暴露在所有 DOM 节点上,它们接收 3 个参数:事件名、事件处理函数、一个布尔值,true 表示在捕获阶段调用事件处理程序,false(默认值)表示在冒泡阶段调用事件处理程序。
<button type="button" id="btn">点我试试</button>
<script>
var btn = document.getElementById('btn');
function fn() {
alert('Hello World');
}
btn.addEventListener('click', fn, false);
// 解绑事件,代码如下
// btn.removeEventListener('click', fn, false);
</script>
/* 方法中包含3个参数,分别是绑定的事件处理属性名称(不包含on)、事件处理函数、是否在捕获时执行事件处理函数(关于事件冒泡和事件捕获下面会介绍)*/
<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>
//IE8级以下版本只支持冒泡型事件,不支持事件捕获所以没有第三个参数
4.DOM3级事件处理
DOM3级事件在DOM2级事件的基础上添加了更多的事件类型,事件类型如下:
- 用户界面UI事件,当用户与页面上的元素交互时触发,如:load、scroll
- 焦点事件,当元素获得或失去焦点时触发,如:blur、focus
- 鼠标事件,当用户通过鼠标在页面执行操作时触发如:dbclick、mouseup
- 滚轮事件,当使用鼠标滚轮或类似设备时触发,如:mousewheel
- 文本事件,当在文档中输入文本时触发,如:textInput
- 键盘事件,当用户通过键盘在页面上执行操作时触发,如:keydown、keypress
- 合成事件,当为IME(输入法编辑器)输入字符时触发,如:compositionstart
- 变动事件,当底层DOM结构发生变化时触发,如:DOMsubtreeModified
同时DOM3级事件也允许使用者自定义一些事件。
DOM事件级别的发展使得事件处理更加完整丰富,而下一个问题就是之前提到的DOM事件模型。「事件冒泡和事件捕获」
二、事件流
事件流:指从页面中接收事件的顺序,有冒泡流和捕获流。
事件捕获:事件由不具体的点接受,从外往内到具体的点接受。
事件冒泡:当子元素与父元素都绑定了同一个事件的时候,触发了子元素的事件之后,先执行子元素的事件处理程序,再冒泡执行父元素的事件处理程序。(阻止事件冒泡event.stopPropagation() )
<body>
<div id="outer">outer
<div id="center">center
<div id="inner" onclick="myFun(123,event)">inner</div>
</div>
</div>
<script>
var outer = document.getElementById('outer')
var center = document.getElementById('center')
var inner = document.getElementById('inner')
// 向上冒泡
// 当我们给inner的父元素和祖先元素也添加点击事件时 一点击inner 所有祖先元素的事件都会被触发事件,这就是事件冒泡现象
//如果不设置传参 DOM会默认提供一个event参数 event 对象只在事件处理程序执行期间存在,一旦执行完毕,就会被销毁。
function myFun(a,event){
console.log(a,event)
}
inner.onclick = function(event){
console.log("inner")//inner center outer 没阻止之前打出的
//阻止事件冒泡
event.stopPropagation();
}
center.onclick = function(){
console.log("center")//inner center
}
outer.onclick = function(){
console.log("outer")//outer
}
</script>
</body>
DOM事件流分为 3 个阶段:事件捕获、到达目标和事件冒泡。事件捕获最先发生,为提前拦截事件提供了可能。然后,实际的目标元素接收到事件。最后一个阶段是冒泡,最迟要在这个阶段响应事件。
注意:所有现代浏览器都支持 DOM 事件流,只有 IE8 及更早版本不支持。
三、事件对象
在 DOM 中发生事件时,所有相关信息都会被收集并存储在一个名为 event 的对象中。这个对象包含了一些基本信息,比如导致事件的元素、发生的事件类型,以及可能与特定事件相关的任何其他数据。 在函数中DOM会默认提供一个event参数 ,event 对象只在事件处理程序执行期间存在,一旦执行完毕,就会被销毁。
3.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>
四、事件委派(事件代理机制)
定义:不将事件处理函数直接绑定到目标dom元素上,而是绑定在其父元素上,这就是事件代理。其好处在于只需要在父元素绑定就可以为所有的子元素代理事件,当子元素动态添加或者删除的时候也不会影响。在子元素动态添加或者删除的时候,使用事件代理。
使用事件代理原因:(为什么要优化)
- 函数是对象,会占用内存,内存中的对象越多,浏览器性能越差
- 注册的事件一般都会指定DOM元素,事件越多,导致DOM元素访问次数越多,会延迟页面交互就绪时间。
- 删除子元素的时候不用考虑删除绑定事件
事件代理好处:
- 减少内存消耗,提高性能
- 动态绑定事件,当子元素动态添加或者删除的时候不会影响。
<body>
<ul id="myLinks">
<li id="li1">Go somewhere</li>
<li id="li2">Do something</li>
<li id="li3">Say hi</li>
</ul>
<script>
var li1=document.getElementById('li1');
li1.onclick=function(){
li1.innerHTML='suzhou';
}
//事件委托 事件委托就是当事件触发时,把要做的事委托给父元素(或父元素的父元素)来处理。
var list = document.getElementById("myLinks");
list.addEventListener("click", function (events) {
console.log(event.target.id)
var target = event.target;
console.log(target);
// e.target: 指的是真正触发事件的那个元素
//获取事件触发元素id
switch (target.id) {
case "li1":
target.innerHTML = 'SuZhou';
break;
case "li2":
target.innerHTML = 'Coding';
break;
case "li3":
target.innerHTML = 'Hi';
break;
}
});
</script>
</body>