Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

事件处理与事件委托 #20

Open
Twlig opened this issue Mar 7, 2022 · 0 comments
Open

事件处理与事件委托 #20

Twlig opened this issue Mar 7, 2022 · 0 comments

Comments

@Twlig
Copy link
Owner

Twlig commented Mar 7, 2022

事件意味着用户或浏览器执行的某种动作。比如,单击(click)、加载(load)、鼠标悬停(mouseover)。为响应事件而调用的函数被称为事件处理程序(或事件监听器)事件处理程序的名字以"on"开头,因此 click 事件的处理程序叫作 onclick,而 load 事件的处理程序叫作 onload。

事件处理程序

事件处理程序有很多指定方式

  1. HTML事件处理程序

    特定元素支持的每个事件都可以使用事件处理程序的名字以 HTML 属性的形式来指定。

    <script> 
     function showMessage() { 
     console.log("Hello world!"); 
     } 
    </script> 
    <input type="button" value="Click Me" onclick="showMessage()"/>
  2. DOM0事件处理程序

    把一个函数赋值给(DOM 元素的)一个事件处理程序属性。

    let btn = document.getElementById("myBtn"); 
    btn.onclick = function() { 
     console.log(this.id); // "myBtn"  this指向该dom元素
    };

    在事件处理程序里通过 this 可以访问元素的任何属性和方法。以这种方式添加事件处理程序是注册在事件流的冒泡阶段的。

    通过将事件处理程序属性的值设置为 null,可以移除通过 DOM0 方式添加的事件处理程序,如下面的例子所示:

    btn.onclick = null;
  3. DOM2事件处理程序

    DOM2 Events 为事件处理程序的赋值和移除定义了两个方法:addEventListener()和 removeEventListener()

    接收 3 个参数:事件名、事件处理函数和一个布尔值,true 表示在捕获阶段调用事件处理程序,false(默认值)表示在冒泡阶段调用事件处理程序

    let btn = document.getElementById("myBtn"); 
    btn.addEventListener("click", () => {  //注意,这里是click不是onclick
     console.log(this.id); 
    }, false);  //在冒泡的时候调用事件处理程序

    注意:事件名前面没有on,有on的是事件处理程序

    通过 addEventListener()添加的事件处理程序只能使用 removeEventListener()并传入与添加时同样的参数来移除。这意味着使用 addEventListener()添加的匿名函数无法移除

    let btn = document.getElementById("myBtn"); 
    btn.addEventListener("click", () => { 
     console.log(this.id); 
     }, false); 
    // 其他代码
    btn.removeEventListener("click", function() { // 没有效果!
     console.log(this.id); 
    }, false);
    let btn = document.getElementById("myBtn"); 
    let handler = function() { 
     console.log(this.id); 
    }; 
    btn.addEventListener("click", handler, false); 
    // 其他代码
    btn.removeEventListener("click", handler, false); // 有效果!
  4. IE事件处理程序

    attachEvent()和 detachEvent()。这两个方法接收两个参数事件处理程序的名字和事件处理函数。因为 IE8 及更早版本只支持事件冒泡,所以使用attachEvent()添加的事件处理程序会添加到冒泡阶段,不需要三个参数。

    var btn = document.getElementById("myBtn"); 
    btn.attachEvent("onclick", function() { 
     console.log("Clicked"); 
    });

    IE与 DOM0 方式区别:

    主要区别是事件处理程序的作用域

    • 使用 DOM0方式时,事件处理程序中的 this 值等于目标元素

    • 使用 attachEvent()时,事件处理程序是在全局作用域中运行的,因此 this 等于 window

事件对象

在 DOM 中发生事件时,所有相关信息都会被收集并存储在 event 对象中。

let btn = document.getElementById("myBtn"); 
btn.onclick = function(event) { 
 console.log(event.type); // "click" 
}; 
btn.addEventListener("click", (event) => { 
 console.log(event.type); // "click" 
}, false);

HTML属性指定的事件也有event对象

<input type="button" value="Click Me" onclick="console.log(event.type)">

event对象中有很多属性和方法,下面介绍最主要的几个:

  1. type

    被触发的事件类型,如click,mouseover等事件名

  2. currentTarget和target

    currentTarget表示当前事件处理程序所在的元素,this始终等于currentTarget。target表示事件目标。

    如果我们在button和body上都添加了事件处理程序:

    • 那么当我们点击button的时
      • button的事件处理程序中的event.currentTarget是button,target也是button。
      • body的事件处理程序中的event.currentTarget是body,target是button
    • 点击body时(没点到body内其他元素)
      • body的事件处理程序中的event.currentTarget是body,target是body

    总结:点击的元素决定着target,当前元素的事件处理程序决定这currentTarget。也就是说,在一个事件流中,target是不变的,但是由于target的父元素也存在事件处理程序,那么父元素的事件处理程序中的currentTarget就是父元素本身。

  3. preventDefault()

    preventDefault()方法用于阻止特定事件的默认动作。比如,链接的默认行为就是在被单击时导航到 href 属性指定的 URL。如果想阻止这个导航行为,可以在 onclick 事件处理程序中取消,如下面的例子所示:

    let link = document.getElementById("myLink"); 
    link.onclick = function(event) { 
     event.preventDefault(); 
    };
  4. stopPropagation()

    stopPropagation()方法用于立即阻止事件流在 DOM 结构中传播,取消后续的事件捕获或冒泡。例如,直接添加到按钮的事件处理程序中调用 stopPropagation(),可以阻止 document.body 上注册的事件处理程序执行。比如:

    let btn = document.getElementById("myBtn"); 
    btn.onclick = function(event) { 
     console.log("Clicked"); 
     event.stopPropagation(); 
    }; 
    document.body.onclick = function(event) { 
     console.log("Body clicked"); 
    };
    //Clicked
    //body click事件处理程序被取消

事件委托

“过多事件处理程序”的解决方案是使用事件委托。事件委托利用事件冒泡,可以只使用一个事件处理程序来管理一种类型的事件。

如下,有三个li元素,点击每个元素都有不同的事件触发

<ul id="myLinks"> 
 <li id="goSomewhere">Go somewhere</li> 
 <li id="doSomething">Do something</li> 
 <li id="sayHi">Say hi</li> 
</ul>

使用事件委托,只要给所有元素共同的祖先节点添加一个事件处理程序,就可以解决问题。

let list = document.getElementById("myLinks"); 
list.addEventListener("click", (event) => { 
 let target = event.target; 
 switch(target.id) { 
 case "doSomething": 
 document.title = "I changed the document's title"; 
 break; 
 case "goSomewhere": 
 location.href = "http:// www.wrox.com"; 
 break; 
 case "sayHi": 
 console.log("hi"); 
 break; 
 } 
});
@Twlig Twlig changed the title JavaScript基础篇之事件处理与事件委托 事件处理与事件委托 Mar 7, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant