-
Notifications
You must be signed in to change notification settings - Fork 66
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
Comments
事件代理就是在祖先级DOM元素绑定一个事件,当触发子孙级DOM元素的事件时,利用事件流的原理来触发绑定在祖先级DOM的事件 |
了解事件代理机制首先要了解浏览器的事件流浏览器的事件流分为事件捕获,处于目标阶段和事件冒泡,事件捕获阶段,事件由父级传递进子级,事件冒泡阶段由子级传递向父级,通过对父级事件的监听,就可以做到同一父级的子级事件的监听。 |
事件代理(事件委托):就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。
用事件委托这么做
|
浏览器的事件代理机制是以浏览器的事件流为基础的. |
事件委托原理:事件冒泡机制。 (微信名:RUN) |
事件流
事件冒泡事件冒泡,即事件最开始由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上转播至最不具体的节点(文档)。 事件捕获事件捕获的思想是不太具体的节点应该更早接收到事件,而最具体的节点最后接收到事件。 事件处理程序
事件对象
事件代理
例子如下: <!--
HTML结构
-->
<ul id="list">
<li class="item-1">1</li>
<li class="item-2">2</li>
<li class="item-3">3</li>
<li class="item-4">4</li>
<li class="item-5">5</li>
</ul>
<p id="text">文本</p>
<!--
javascript 代码
-->
<script>
'use strict';
list.addEventListener('click', event => {
if (event.target.className.indexOf('item-') === 0) {
text.innerHTML = event.target.innerHTML;
};
});
</script> |
事件放到父元素上去监听,判断每次点击的元素是不是就是想绑定的元素。 |
事件代理就是通过事件冒泡把所点击的元素绑定在他的父元素上。 |
事件代理 就是在祖先级DOM元素绑定一个事件,当触发子孙级DOM元素的事件时,利用事件流的原理来触发绑定在祖先级DOM的事件。 事件流DOM(文档对象模型)结构是一个树型结构,当一个HTML元素产生一个事件时,该事件会在元素结点与根结点之间的路径传播,路径所经过的结点都会收到该事件,这个传播过程可称为DOM事件流。 因为历史的原因,IE最开始实现实现事件流的方式:冒泡事件(event bubbling),Netscape提出了另外一种事件流方式:事件捕获(event capturing),不同的浏览器实现上有一些差别,用起来就有些繁琐。幸好现代浏览器都实现了W3C制定的"DOM2级事件","DOM2级事件"把事件流分为三个阶段,捕获阶段、目标阶段、冒泡阶段。 这个问题回答起来,有些无从下手的感觉,事件流的概念不是很好描述,之前个人的理解很浅显。 |
浏览器的代理机制原理的就是冒泡机制
|
代理机制的原理是将元素的事件委托给它的父级或者更外级元素处理。 |
浏览器事件代理机制的原理浏览器事件代理本质是将事件委托给它的父级元素或者祖先元素。利用的是事件冒泡的原理。 不采用事件委托function() {
let ul = document.getElementById('ul');
let lis = ul.getElementsByTagName('li');
for(let i = 0, l = lis.length; i< l; i++) {
llis[i].onClick = function() {
alert('li element')
}
}
} 采用事件委托将click事件代理到父元素 function() {
let ul = document.getElementById('ul');
ul.addEventListener('click', function(e){
let ev = e || event;
let target = ev.target || ev.srcElement;
if(target.nodeName.toLowerCase === 'li') {
alert(target)
}
})
} |
浏览器事件代理机制事件流事件流描述的是从页面中接受事件的顺序。分为事件捕获和事件冒泡。
addEventListeb(event, function, useCapture), 第三个参数默认为false, 即使用时间冒泡,若为true则使用事件捕获的机制。 事件代理通俗来讲是将元素的事件函数处理交由其他对象处理。它允许您避免向特定节点添加事件侦听器,我们这里所谈论的事件委托,与冒泡捕获流程相关,因此事件委托在此场景指的是子对象的处理事件交由父对象处理。 好像很多博客都是举的ul和li的例子:
如果直接对li 节点进行click 监听,需要绑定多个事件监听器, 但如果利用冒泡只监听ul, 每次事件触发的时候,确定触发的目标是不是li的某个具体元素,这样,就可以省去建立多个监听器(尤其是对li 进行动态增减的时候)
|
事件代理就是在祖先级dom元素上绑定一个事件,当触发子孙级元素的事件时,利用事件流的原理来触发绑定在祖先上的事件。 |
基于事件冒泡, |
事件代理就是在祖先级DOM元素绑定一个事件,当触发子孙级DOM元素的事件时,利用事件流的原理来触发绑定在祖先级DOM的事件。事件代理是基于事件冒泡。 |
事件流事件捕获从window对象传到目标节点(上层到下层),成为捕获阶段 事件冒泡从目标节点传到window对象(下层到上层) ###事件代理(事件委托)
IE8打印出来的事件 |
|
|
事件捕获
事件委托,又称为事件代理:通俗来讲是将元素的事件函数处理交由其他对象处理。它允许您避免向特定节点添加事件侦听器,我们这里所谈论的事件委托,与冒泡捕获流程相关,因此事件委托在此场景指的是子对象的处理事件交由父对象处理。 上代码
|
减轻每个item都要绑定的开销 |
html元素在页面上可以看做一个同心圆,当点击一个区域的时候等同于点击了包括这个点击点的很多区域。不同元素只要包含了这个点击点的都会接受到这个事件。事件流是指事件被接收的顺序。事件流分为两种,事件冒泡和事件捕获。事件冒泡是指子元素先接收事件,然后父元素再接收事件。事件捕获就是父元素先接受事件,然后子元素再接收事件。 事件代理就是利用了事件冒泡的机制,子元素的事件会冒泡到父元素,这样做的好处是:
|
事件代理就是在祖先级DOM元素绑定一个事件,当触发子孙级DOM元素的事件时,利用事件流的原理来触发绑定在祖先级DOM的事件。 事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件,是对“事件处理程序过多”问题的解决方案。 在一个复杂的web应用程序中,如果对每个可单击的元素都添加事件处理程序,那么结果会有数不清的代码用于添加事件处理程序。此时,可以使用事件委托技术解决这个问题。使用事件委托,只需在DOM树中尽量最高的层次上添加一个事件处理程序。 |
事件流事件从页面接受的顺序 捕获和冒泡都是为了解决事件流的在页面的发生顺序 事件捕获从事件的最外层开始触发 最后到具体的元素 事件冒泡从事件的最内部元素开始 到最外层 和捕获相反 addEventListener(e,fn,b) 默认是false 是冒泡 true 是捕获如果想阻止冒泡 可以是用stopPropagetion() (preventDefault()阻止浏览器默认行为)
事件委托事件委托又叫事件代理把元素的事件处理函数 交给别的对象来处理
|
事件流在说浏览器事件代理机制原理之前,我们首先了解一下事件流的概念,早期浏览器,IE采用的是事件捕获事件流,而Netscape采用的则是事件冒泡。"DOM2级事件"把事件流分为三个阶段,捕获阶段、目标阶段、冒泡阶段。现代浏览器也都遵循此规范。 事件代理机制的原理事件代理又称为事件委托,在祖先级 DOM 元素绑定一个事件,当触发子孙级DOM元素的事件时,利用事件冒泡的原理来触发绑定在祖先级 DOM 的事件。因为事件会从目标元素一层层冒泡至 document 对象。 为什么要事件代理?
addEventListeneraddEventListener 接受3个参数,分别是要处理的事件名、实现了 EventListener 接口的对象或者是一个函数、一个对象/一个布尔值。 target.addEventListener(type, listener[, options]);
target.addEventListener(type, listener[, useCapture]); options(对象) | 可选
useCapture(Boolean) | 可选
document.addEventListener('click', function (e) {
console.log(e.target);
/**
* 捕获阶段调用调用事件处理程序,eventPhase是 1;
* 处于目标,eventPhase是2
* 冒泡阶段调用事件处理程序,eventPhase是 3;
*/
console.log(e.eventPhase);
}, false); 与 |
事件代理是指把要绑定的事件绑定在父元素上面。利用的是事件冒泡的机制,在父元素上捕获事件。在工作中非常常用。 |
为了性能优化,把子元素上所需绑定的事件统一绑定到指定的父元素上,当触发了子元素,实际上第一响应的是父元素,会将对应事件往下传到对应元素,该阶段不执行事件。到目标阶段执行事件。再开始冒泡阶段,向上层元素传播事件,如果有元素绑定了该事件同样触发。
|
一般的事件机制是先从document到目标事件再从目标事件到document,事件一被称为捕获,事件2呗称为冒泡,为了节约性能我们一般采用冒泡的方式对事件来进行处理。
|
事件JavaScript与HTML之间的交互是通过
像鼠标点击、页面或图像载入、键盘按键等操作。事件通常与函数配合使用,当事件发生时函数才会执行。 事件名称: 响应某个事件的函数就是事件处理程序(事件侦听器)。 事件处理程序函数名称: 事件流
IE和Netscape开发团队(网景)居然提出了差不多是完全相反的事件流的概念。 IE的事件流是事件冒泡流,而网景的事件流是事件捕获流。 事件冒泡即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。
如果你单击了页面中的div元素,那么这个click事件会按照如下顺序传播:
事件捕获事件捕获的思想是不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件。 仍以上面的代码做例子,那么单击div元素就会以下列顺序触发click事件:
DOM事件流
首先发生的是事件捕获,为截获事件提供了机会。然后是实际的目标接收到事件。最后一个阶段是冒泡阶段,可以在这个阶段对事件作出相应。 事件处理程序
HTML事件处理程序它是写在HTML里的,是全局作用域。
当我们需要使用一个复杂的函数时,将js代码写在这里,显然很不合适,所以有了下面这种写法:
这样会出现一个时差问题,当用户在HTML元素出现一开始就进行点击,有可能js还没加载好,这时候就会报错。但我们可以将函数封装在try-catch来处理:
同时,一个函数的改变,同时可能会涉及html和js的修改,这样是很不方便的,综上,才有了DOM0 级事件处理程序。 DOM0 级事件处理程序
可以看到button.onlick这种形式,这里事件处理程序作为btn对象的方法,是局部作用域。 所以我们可以用
如果我们尝试添加两个事件:
结果输出 DOM2 级事件处理程序(不支持IE)进一步规范之后,有了DOM2 级事件处理程序,其中定义了两个方法:
具体用法看: https://developer.mozilla.org/zh-CN/docs/Web/API/EventTarget/addEventListener 这两个方法都有三个参数:
这时候,这两个事件处理程序都能够被触发,说明可以绑定多个事件处理程序,但是注意,如果定义了一模一样的监听方法,是会发生覆盖的,即同样的事件和事件流机制下相同方法只会触发一次。比如:
这样的话,事件处理程序只会执行一次。 但是要注意,如果同一个监听事件分别为“事件捕获”和“事件冒泡”注册了一次,一共两次,这两次事件需要分别移除。两者不会互相干扰。 这时候的this指向该元素的引用。这里事件触发的顺序是添加的顺序。 IE事件处理程序对于IE来说,在IE9之前,你必须使用 IE事件处理程序中有类似DOM2 级事件处理程序的两个方法:
它们都接收两个参数:
之所以没有和DOM2 级事件处理程序中类似的第三个参数,是因为IE8及更早版本只支持冒泡事件流。
注意:这里事件触发的顺序不是添加的顺序而是添加顺序的想法顺序。 使用 事件对象事件对象是用来记录一些事件发生时的相关信息的对象。事件对象只有事件发生时才会产生,并且只能是事件处理程序内部访问,在所有事件处理函数运行结束后,事件对象就被销毁。 2级DOM中的Event对象常用的属性和方法:
IE中的Event对象常用的属性和方法:
兼容性事件对象也存在一定的兼容性问题,在IE8及以前版本之中,通过设置属性注册事件处理程序时,调用的时候并未传递事件对象,需要通过全局对象
事件代理机制的原理
看个例子:
上面代码中, 如果希望事件到某个节点为止,不再传播,可以使用事件对象的
上面代码中, 注意:
上面代码中, 如果想要彻底阻止这个事件的传播,不再触发后面所有
事件代理机制的优点和局限性优点
局限性
参考: |
在理解浏览器事件代理机制的原理前,先了解一下事件流,事件流描述的是从页面中接收事件的顺序。 <!DOCTYPE html>
<html>
<head>
<title>Event Bubbling Example</title>
</head>
<body>
<div id="myDiv">Click Me</div>
</body>
</html>
如果在一个复杂的 Web 应用程序中,对所有可单击的元素都采用这种方式,那么结果就会有数不 清的代码用于添加事件处理程序。此时,可以利用事件委托技术解决这个问题。使用事件委托,只需在 DOM 树中尽量最高的层次上添加一个事件处理程序,如下面的例子所示。 var list = document.getElementById("myLinks");
EventUtil.addHandler(list, "click", function(event){
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
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": 9 alert("hi");
break; }
}); |
事件流的概念:
passive: Boolean。true 表示 listener 永远不会调用 preventDefault()。如果 listener 仍然调用了这个函数,客户端将会忽略它并抛出一个控制台警告。默认是 false。 useCapture(Boolean) | 可选 useCapture 默认为 false。表示冒泡阶段调用事件处理程序,若设置为 true,表示在捕获阶段调用事件处理程序。 如将页面中的所有click事件都代理到document上: document.addEventListener('click', function (e) { }, false); |
浏览器事件代理机制原理 首先介绍下事件流吧 ie最早提出事件流的概念 认为事件流是由目标元素逐级向上传播 即事件冒泡 netspace提出刚好相反的意见 即事件是由根元素逐级向下传播至目标元素即事件捕获 现代浏览器都遵从w3c制定的dom2级事件流 即事件流分为三个阶段 事件捕获 目标阶段 事件冒泡 dom2级添加和移除事件的写法大概如下: 其他浏览器 ie浏览器 注意 事件代理 事件代理的优点
|
事件代理
事件流
早期浏览器,IE采用的事件捕获事件流,Netscape采用的是事件冒泡。 事件捕获
事件冒泡
|
该部分参考 点我查看这篇文章,
优点:
需要注意的地方
|
No description provided.
The text was updated successfully, but these errors were encountered: