JavaScript 이벤트의 해석
1. 이벤트의 기본 개념
이벤트는 웹 페이지를 열거나 그 이후에 문서나 브라우저에서 발생하는 특정 상호 작용 순간을 나타냅니다. 브라우저가 로드됩니다. load
이벤트가 트리거됩니다. 마우스를 요소 위로 가져가면 hover
이벤트가 트리거됩니다. code>click 이벤트 등이 트리거됩니다. load
事件,当鼠标悬浮于某一个元素上时会触发 hover
事件,当鼠标点击某一个元素时会触发 click
事件等等。
事件处理就是当事件被触发后,浏览器响应这个事件的行为,而这个行为所对应的代码即为事件处理程序。
2. 事件操作:监听与移除监听
2.1 监听事件
浏览器会根据一些事件作出相对应的事件处理,事件处理的前提是需要监听事件,监听事件的方法主要有以下三种:
2.1.1 HTML 内联属性
即在 HTML 元素里直接填写与事件相关的属性,属性值为事件处理程序。示例如下:
<button></button>
onclick
对应着 click
事件,所以当按钮被点击后,便会执行事件处理程序,即控制台输出 You clicked me!
。
不过我们需要指出的是,这种方式将 HTML 代码与 JavaScript 代码耦合在一起,不利于代码的维护,所以应该尽量避免使用这样的方式。
2.1.2 DOM 属性绑定
通过直接设置某个 DOM 节点的属性来指定事件和事件处理程序,上代码:
const btn = document.getElementById("btn"); btn.onclick = function(e) { console.log("You clicked me!"); };
上面示例中,首先获得 btn 这个对象,通过给这个对象添加 onclick
属性的方式来监听 click
事件,这个属性值对应的就是事件处理程序。这段程序也被称作 DOM 0 级事件处理程序。
2.1.3 事件监听函数
标准的事件监听函数如下:
const btn = document.getElementById("btn"); btn.addEventListener("click", () => { console.log("You clicked me!"); }, false);
上面的示例表示先获得表示节点的 btn 对象,然后在这个对象上面添加了一个事件监听器,当监听到 click
事件发生时,则调用回调函数,即在控制台输出 You clicked me!
。addEventListener
函数包含了三个参数 false,第三个参数的含义在后面的事件触发三个阶段之后再讲解。这段程序也被称作 DOM 2 级事件处理程序。IE9+、FireFox、Safari、Chrome 和 Opera 都是支持 DOM 2 级事件处理程序的,对于 IE8 及以下版本,则用 attacEvent()
函数绑定事件。
所以我们可以写一段具有兼容性的代码:
function addEventHandler(obj, eventName, handler) { if (document.addEventListener) { obj.addEventListener(eventName, handler, false); } else if (document.attachEvent) { obj.attachEvent("on" + eventName, handler); } else { obj["on" + eventName] = handler; } }
2.2 移除事件监听
在为某个元素绑定了一个事件后,如果想接触绑定,则需要用到 removeEventListener
方法。看如下例子:
const handler = function() { // handler logic } const btn = document.getElementById("btn"); btn.addEventListener("click", handler); btn.removeEventListener("click", handler);
需要注意的是,绑定事件的回调函数不能是匿名函数,必须是一个已经被声明的函数,因为解除事件绑定时需要传递这个回调函数的引用。
同样,IE8 及以下版本也不支持上面的方法,而是用 detachEvent
이벤트 처리
는 이벤트가 트리거될 때 이벤트에 응답하는 브라우저의 동작이며, 이 동작에 해당하는 코드가이벤트 핸들러
입니다. <p></p>2. 이벤트 작업: 모니터링 및 제거2.1 이벤트 모니터링
이벤트 처리의 전제는 이벤트를 모니터링하는 세 가지 주요 방법입니다. : :
2.1.1 HTML 인라인 속성
즉, HTML 요소에 이벤트 관련 속성을 직접 채우는 것이며, 속성 값이 이벤트 핸들러입니다. 예는 다음과 같습니다.
const handler = function() { // handler logic } const btn = document.getElementById("btn"); btn.attachEvent("onclick", handler); btn.detachEvent("onclick", handler);
onclick
은 click
이벤트에 해당하므로 버튼을 클릭하면 이벤트 핸들러가 실행됩니다. 즉, 콘솔 출력 저를 클릭하셨습니다!
. 그러나 이 방법은 HTML 코드와 JavaScript 코드를 결합하는 방식이므로 코드 유지 관리에 도움이 되지 않으므로 이 방법은 최대한 피해야 합니다.
2.1.2 DOM 속성 바인딩
DOM 노드의 속성을 직접 설정하여 이벤트 및 이벤트 핸들러를 지정합니다. 위 코드:
function removeEventHandler(obj, eventName, handler) { if (document.removeEventListener) { obj.removeEventListener(eventName, handler, false); } else if (document.detachEvent) { obj,detachEvent("on" + eventName, handler); } else { obj["on" + eventName] = null; } }
위 예에서는 먼저 Add를 통해 btn 객체를 얻습니다. 이 속성의 값은 이벤트 핸들러에 해당합니다. 이 프로그램은 DOM 레벨 0 이벤트 핸들러라고도 합니다. 2.1.3 이벤트 리스닝 함수
표준 이벤트 리스닝 함수는 다음과 같습니다.
<div> <p>你猜,目标在这里还是<span>那里</span>。</p> </div>
위의 예는 노드를 나타내는 btn 객체를 먼저 얻은 후 이벤트 리스너를 추가하는 것을 나타냅니다. click
이벤트가 모니터링되면 콜백 함수가 호출됩니다. 즉, You clicked me!
가 콘솔에 출력됩니다. addEventListener
함수에는 false라는 세 가지 매개변수가 포함되어 있습니다. 세 번째 매개변수의 의미는 이벤트 트리거의 세 단계 후에 설명됩니다. 이 프로그램은 DOM 레벨 2 이벤트 핸들러라고도 합니다. IE9+, FireFox, Safari, Chrome 및 Opera는 모두 DOM 레벨 2 이벤트 핸들러를 지원합니다. IE8 이하에서는 attacEvent()
함수를 사용하여 이벤트를 바인딩합니다.
// HTML <ul id="list"> <li>Item 1</li> <li>Item 2</li> <li>Item 3</li> <li>Item 4</li> <li>Item 5</li> </ul> // JavaScript var list = document.getElementById("list"); list.addEventListener("click", function(e) { console.log(e.target); });
removeEventListener< /code>를 사용해야 합니다. 방법. 다음 예를 보세요. 🎜<div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">const ele = document.getElementById("ele");
ele.addEventListener("click", function() {
console.log("ele-click");
}, false);
document.addEventListener("click", function() {
console.log("document-click");
}, false);</pre><div class="contentsignin">로그인 후 복사</div></div><div class="contentsignin">로그인 후 복사</div></div>🎜바인딩된 이벤트의 콜백 함수는 익명 함수가 될 수 없지만 이벤트 바인딩을 해제할 때 이 콜백 함수의 참조를 전달해야 하기 때문에 선언된 함수여야 합니다. 🎜🎜마찬가지로 IE8 이하 버전에서는 위의 방법을 지원하지 않으므로 대신 <code>detachEvent
를 사용하세요. 🎜const ele = document.getElementById("ele"); ele.addEventListener("click", function(e) { console.log("ele-click"); e.stopPropagation(); // 阻止事件冒泡 }, false); document.addEventListener("click", function(e) { console.log("document-click"); }, false);
function preventBubble(e) { if (!e) { const e = window.event; } e.cancelBubble = true; if (e.stopPropagation) { e.stopPropagation(); } }
<div> <p>你猜,目标在这里还是<span>那里</span>。</p> </div>
当我们点击“那里”的时候,目标节点是<span></span>
,点击“这里”的时候,目标节点是<p></p>
,而当我们点击<p></p>
区域之外,<p></p>
区域之内时,目标节点就是<p></p>
。
3.3 冒泡阶段
当事件到达目标节点之后,就会沿着原路返回,这个过程有点类似水泡从水底浮出水面的过程,所以称这个过程为冒泡阶段。
针对这个过程,wilsonpage 做了一个 DEMO,可以非常直观地查看这个过程。
现在再看 addEventListener(eventName, handler, useCapture)
函数。第三个参数是 useCapture,代表是否在捕获阶段进行事件处理, 如果是 false, 则在冒泡阶段进行事件处理,如果是 true,在捕获阶段进行事件处理,默认是 false。这么设计的主要原因是当年微软和 netscape 之间的浏览器战争打得火热,netscape 主张捕获方式,微软主张冒泡方式,W3C 采用了折中的方式,即先捕获再冒泡。
4、事件委托
上面我们讲了事件的冒泡机制,我们可以利用这一特性来提高页面性能,事件委托便事件冒泡是最典型的应用之一。
何谓“委托”?在现实中,当我们不想做某件事时,便“委托”给他人,让他人代为完成。JavaScript 中,事件的委托表示给元素的父级或者祖级,甚至页面,由他们来绑定事件,然后利用事件冒泡的基本原理,通过事件目标对象进行检测,然后执行相关操作。看下面例子:
// HTML <ul id="list"> <li>Item 1</li> <li>Item 2</li> <li>Item 3</li> <li>Item 4</li> <li>Item 5</li> </ul> // JavaScript var list = document.getElementById("list"); list.addEventListener("click", function(e) { console.log(e.target); });
上面的例子中,5 个列表项的点击事件均委托给了父元素 <ul id="list"></ul>
。
先看看事件委托的可行性。有人会问,当事件不是加在某个元素上的,如何在这个元素上触发事件呢?我们就是利用事件冒泡的机制,事件流到达目标元素后会向上冒泡,此时父元素接收到事件流便会执行事件执行程序。有人又会问,被委托的父元素下面如果有很多子元素,怎么知道事件流来自于哪个子元素呢?这个我们可以从事件对象中的 target
属性获得。事件对象下面会详细讲解。
我们再来看看为什么需要事件委托。
减少事件绑定。上面的例子中,也可以分别给每个列表项绑定事件,但利用事件委托的方式不仅省去了一一绑定的麻烦,也提升了网页的性能,因为每绑定一个事件便会增加内存使用。
可以动态监听绑定。上面的例子中,我们对 5 个列表项进行了事件监听,当删除一个列表项时不需要单独删除这个列表项所绑定的事件,而增加一个列表项时也不需要单独为新增项绑定事件。
看了上面的例子和解释,我们可以看出事件委托的核心就是监听一个 DOM 中更高层、更不具体的元素,等到事件冒泡到这个不具体元素时,通过 event 对象的 target 属性来获取触发事件的具体元素。
5、阻止事件冒泡
事件委托是事件冒泡的一个应用,但有时候我们并不希望事件冒泡。比如下面的例子:
const ele = document.getElementById("ele"); ele.addEventListener("click", function() { console.log("ele-click"); }, false); document.addEventListener("click", function() { console.log("document-click"); }, false);
我们本意是当点击 ele 元素区域时显示 "ele-click",点击其他区域时显示 "document-click"。但是我们发现点击 ele 元素区域时会依次显示 "ele-click" "document-click"。那是因为绑定在 ele 上的事件冒泡到了 document 上。想要解决这个问题,只需要加一行代码:
const ele = document.getElementById("ele"); ele.addEventListener("click", function(e) { console.log("ele-click"); e.stopPropagation(); // 阻止事件冒泡 }, false); document.addEventListener("click", function(e) { console.log("document-click"); }, false);
我们还能用 e.cancelBubble = true
来替代 e.stopPropagation()
。网上的说法是 cancelBubble
仅仅适用于 IE,而 stopPropagation
适用于其他浏览器。但根据我实验的结果,现代浏览器(IE9 及 以上、Chrome、FF 等)均同时支持这两种写法。为了保险起见,我们可以采用以下代码:
function preventBubble(e) { if (!e) { const e = window.event; } e.cancelBubble = true; if (e.stopPropagation) { e.stopPropagation(); } }
6、event 对象
Event 对象代表事件的状态,比如事件在其中发生的元素、键盘按键的状态、鼠标的位置、鼠标按钮的状态。当一个事件被触发的时候,就会创建一个事件对象。
我们用下面的代码打印出事件对象:
<div id="list"> <li>Item 1</li> <li>Item 2</li> </div> <script> var list = document.getElementById("list"); list.addEventListener("click", function(e) { console.log(e); }); </script>
chrome 49 的运行结果如下:
下面介绍一些比较常用的属性和方法。
target、 srcElement、 currentTarget 和 relatedTarget、fromElement、 toElement
target 与 srcElement 完全相同;
target은 이벤트를 트리거한 요소를 참조하고, currentTarget은 이벤트가 바인딩된 요소를 참조합니다.
관련Target: 이벤트의 대상 노드와 관련된 노드입니다. 마우스오버 이벤트의 경우 이 속성은 대상 노드 위로 이동할 때 마우스 포인터가 떠난 노드입니다. mouseout 이벤트의 경우 이 속성은 마우스 포인터가 대상을 떠날 때 들어가는 노드입니다.
이 속성은 다른 유형의 이벤트에는 유용하지 않습니다.fromElement 및 toElement는 mouseover 및 mouseout 이벤트에만 유효합니다.
위의 예를 들어 설명을 위해 <li>Item 1</li>
时,target 就是 <li>Item 1</li>
元素,而 currentTarget 是 <p id="list"></p>
를 클릭하세요.
clientX/Y、 화면
clientX/Y: 클릭 위치는 브라우저 콘텐츠 영역의 왼쪽 상단을 기준으로 합니다. <p></p>screenX/Y: 클릭 위치는 화면의 왼쪽 상단을 기준으로 합니다.
- pageX/Y: 클릭 위치는 전체 페이지에 상대적입니다. 왼쪽 상단 모서리의 위치
- <p></p> pageX/Y와 clientX/Y는 일반적으로 동일하며 스크롤할 때만 다릅니다. 바가 나타납니다.
- <p></p> altKey, ctrlKey, ShiftKey
- <p></p> altKey: 이벤트가 트리거될 때 "ALT" 키를 눌렀는지 여부를 반환합니다.
- <p></p> ctrlKey: 이벤트가 트리거될 때 "CTRL" 키를 눌렀는지 여부를 반환합니다. . 다음
- <p></p> shiftKey: 이벤트가 트리거될 때 "SHIFT" 키를 눌렀는지 여부를 반환합니다.
- 기타 속성
- <p></p> type: 현재 이벤트 개체가 나타내는 이벤트의 이름을 반환합니다.
bubbles: 이벤트가 버블 이벤트 유형인지 여부를 나타내는 부울 값을 반환합니다.
cancelable: 이벤트에 취소 가능한 기본 작업이 있을 수 있는지 여부를 나타내는 부울 값을 반환합니다.
eventPhase: 현재를 반환합니다. 이벤트 전파 단계에는 Event.CAPTURING_PHASE, Event.AT_TARGET, Event.BUBBLING_PHASE의 세 가지 값이 있으며 해당 값은 각각 캡처 단계, 일반 이벤트 전달 및 버블링 단계를 나타내는 1, 2 및 3입니다.
- path: 버블링 단계를 통과한 노드 <p></p>
- Method<p></p>
- preventDefault(): 이벤트와 관련된 기본 작업을 수행하지 않도록 브라우저에 알립니다. <p></p>
- stopPropagation(): 버블링 방지 ; <p></p>
- 추천 학습: "<p></p>js 기본 튜토리얼