目录
HTML DOM允许JS对HTML事件作出反应,当对某个元素进行操作时执行JavaScript代码。
JavaScript与HTML之间的交互是通过事件实现的。事件就是文档或浏览器窗口中发生的一些特定的交互瞬间。
获取事件源
绑定事件(注册事件)
采用函数赋值的方式添加事件处理程序
简单来说,事件流就是事件执行的顺序。DOM树里会有许多元素嵌套,当我们同时给父子元素设置了事件时,父子元素会以一种特定的顺序来执行事件,这就是事件流。并且嵌套的层级不限,事件会贯穿当前元素与根元素。
DOM支持两种事件流:冒泡型事件流 | 捕获型事件流
- <style>
- * {
- color: white;
- font-size: 20px;
- }
- #outer {
- width: 300px;
- height: 300px;
- background-color: lightpink;
- }
- #center {
- width: 200px;
- height: 200px;
- background-color: lightgreen;
- }
- #inner {
- width: 100px;
- height: 100px;
- background-color: lightskyblue;
- }
- style>
- head>
- <body>
- <div id="outer">
- outer
- <div id="center">
- center
- <div id="inner">innerdiv>
- 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>
第一次只在 inner 上添加了事件,因此点击 inner 时只有 inner 上的事件被触发:
第二次我们在 center 和 outer 上也添加了点击事件,虽然我们只点击了 inner 但是 center 与 outer 上的事件也被触发了:
事实上,这个click事件还会沿着DOM树一直到body,html,document。
在阻止冒泡之前,我们要知道一个对象叫 event ,它代表事件的状态,比如事件在其中发生的元素,键盘状态,鼠标位置,鼠标按钮状态等……
事件通常与函数结合使用,函数不会在事件发生前被执行!
直接在对应方法中使用 event.stopPropagation() 便可阻止事件冒泡。
注意:如果点击方法时需要同时传递其他参数和event,直接传递event这个单词即可
在捕获型事件流中,click事件会首先被document捕获,然后沿着DOM树依次向下,直到事件的目标元素。
由于旧版本浏览器不支持,因此实际当中几乎不会使用事件捕获。通常建议使用事件冒泡,特殊情况下可以使用事件捕获。
事件捕获、到达目标、事件冒泡
为响应事件而调用的函数被称为事件处理程序(或事件监听器)。事件处理程序的名字以"on"开头,因此 click 事件的处理程序叫作 onclick,而 load 事件的处理程序叫作 onload。有很多方式可以指定事件处理程序。
特定元素支持的每个事件都可以使用事件处理程序的名字以 HTML 属性的形式来指定。此时的属性值必须是能够执行的 JavaScript 代码。例如,要在按钮被点击时执行某些 JavaScript 代码,可以使用以下 HTML 属性:
<button onclick="console.log('Clicked')">点我啊button>
点击这个按钮后,控制台会输出一条消息。
注意,因为属性的值是 JavaScript 代码,所以不能在未经转义的情况下使用 HTML 语法字符,比如和号(&)、双引号(")、小于号(<)和大于号(>)。此时,为了避免使用 HTML 实体,可以使用单引号代替双引号。如果确实需要使用双引号,则要把代码改成下面这样:
<button onclick="console.log("Clicked")">点我啊button>
在 HTML 中定义的事件处理程序可以包含精确的动作指令,也可以调用在页面其他地方定义的方法。
- <button onclick="showMsg()">点我啊button>
- <script>
- function showMsg() {
- console.log('Hello Wolrd!');
- }
- script>
-
-
- 在这个函数中,this 值相当于事件的目标元素,如下面的例子所示:
-
- <button onclick="this.innerHTML = '我被改变了'">点我啊button>
要使用 JavaScript 指定事件处理程序,必须先取得要操作对象的引用。每个元素(包括 window 和 document)都有通常小写的事件处理程序属性,比如 onclick。只要把这个属性赋值为一个函数即可:
- <script>
- // DOM0
- var btn = document.getElementById('btn')
- btn.onclick = function(event){
- console.log('我被打中了');
- console.log(this.id); //btn
-
- }
- script>
点击按钮,这段代码会显示元素的 ID。这个 ID 是通过 this.id 获取的。不仅仅是 id,在事件处理程序里通过 this 可以访问元素的任何属性和方法。以这种方式添加事件处理程序是注册在事件流的冒泡阶段的。在DOM2 中也如此。
移除事件程序:
btn.onclick = null; // 移除事件处理程序
把事件处理程序设置为 null,再点击按钮就不会执行任何操作了。
DOM2 Events 为事件处理程序的赋值和移除定义了两个方法:
addEventListener()和removeEventListener()
这两个方法暴露在所有 DOM 节点上,它们接收 3 个参数:事件名、事件处理函数和一个布尔值,true 表示在捕获阶段调用事件处理程序,false(默认值)表示在冒泡阶段调用事件处理程序。
-
- <script>
-
- var btn = document.getElementById('btn')
-
- // 单纯添加事件处理程序
- btn.addEventListener('click',function(){
- console.log('怎么又被打中了');
- },false)
- btn.addEventListener('click',function(){
- console.log(this.id); // btn
- })
- script>
这里给按钮添加了两个事件处理程序。多个事件处理程序以添加顺序来触发,因此前面的代码会先打印'我被点击了',然后显示元素ID。
通过 addEventListener()添加的事件处理程序只能使用 removeEventListener()并传入与添加时同样的参数来移除。这意味着使用 addEventListener()添加的匿名函数无法移除,如:
- <script>
- var btn = document.getElementById("btn");
- btn.addEventListener("click", function () {
- console.log('我被点击了');
- }, false);
- // 移除
- btn.removeEventListener("click", function () {
- console.log(this.id); //没有效果
- })
- script>
解绑事件要具名:
这个例子通过 addEventListener()添加了一个匿名函数作为事件处理程序。然后,又以看起来相同的参数调用了 removeEventListener()。但实际上,第二个参数与传给 addEventListener()的完全不是一回事。传给 removeEventListener()的事件处理函数必须与传给 addEventListener()的是同一个,如:
- <script>
- var btn = document.getElementById("btn");
- // 新增一个方法
- var handler = function () {
- console.log(this.id);
- }
- btn.addEventListener("click", handler, false);
- // 移除
- btn.removeEventListener("click", handler, false); // 有效果
- script>
这个例子有效,因为调用 addEventListener()和 removeEventListener()时传入的是同一个函数。
在 DOM 中发生事件时,所有相关信息都会被收集并存储在一个名为 event 的对象中。这个对象包含了一些基本信息,比如导致事件的元素、发生的事件类型,以及可能与特定事件相关的任何其他数据。例如,鼠标操作导致的事件会生成鼠标位置信息,而键盘操作导致的事件会生成与被按下的键有关的信息。所有浏览器都支持这个 event 对象,尽管支持方式不同。
注意:event 对象只在事件处理程序执行期间存在,一旦执行完毕,就会被销毁。
用于阻止特定事件的默认动作。比如,链接的默认行为就是在被单击时导航到 href 属性指定的 URL或是修改表单提交的默认事件。如果想阻止这些行为,可以在 onclick 事件处理程序中取消,如:
- <button id="btn">提交button>
-
- <script>
- // 组织a事件的默认事件发生
- var a = document.getElementsByTagName('a')[0]
- a.onclick = function(event){
- event.preventDefault();
- console.log('a被点中了');
- }
- var f = document.getElementById('btn')
- btn.onclick = function(event){
- event.preventDefault();
- console.log('┗|`O′|┛ 嗷~~');
- }
- script>
事件委托:也就是事件代理,也就是将原本绑定在子元素身上的事件 委托 给父元素。让父元素去监听事件。其原理是利用事件冒泡。这意味着可以为整个页面指定一个 onclick 事件处理程序,而不用为每个可点击元素分别指定事件处理程序。
优点:大大减少DOM操作和浏览器的重排和重绘,节省内存占用。也可以实现当新增对象时无需再次对其绑定事件。
如·:
这里的 HTML 包含 3 个列表项,在被点击时应该执行某个操作。对此,通常的做法是像这样指定 3个事件处理程序:
使用事件委托,只要给所有元素共同的祖先节点添加一个事件处理程序,就可以解决代码大段雷同的问题:
这里只给