Events are the beating heart of JavaScript applications and the glue that holds everything together. Events occur when we perform certain types of interactions with web pages in the browser. An event might be a user clicking on something, moving the mouse over a specific element, or pressing certain keys on the keyboard. Events may also be things that happen in the web browser, such as a web page loading, or the user scrolling or resizing the window.
By using JavaScript, you can listen for specific events to occur and specify that certain events occur in response to those events.
In the long history of evolution, we have bid farewell to the inline event handling method (using event handlers directly within HTML elements). Today's events are already an important part of the DOM. Unfortunately, IE continues to retain the event model first implemented in IE4.0, and has not made much changes in subsequent IE versions. This means that IE It still uses a proprietary event model (bubble type), while other mainstream browsers did not support the DOM standard event processing model - capture type and bubbling type - until the DOM level 3 regulations were finalized.
Historical reason: The W3C specification did not define any events in DOM Level 1. It was not until DOM Level 2 released in November 2000 that a small subset was defined, which is already provided in DOM Level 2. In order to provide a more detailed and granular way to control events in Web pages, complete events were finally finalized in the 2004 DOM Level 3 specification. Because IE4 was launched in 1995 and had implemented its own event model (bubble type), there was no DOM standard at all at that time. However, in the subsequent DOM standard specification process, IE's event model has been absorbed into it.
Currently, in addition to IE browser, other mainstream Firefox, Opera, and Safari all support the standard DOM event processing model. IE still uses its own proprietary event model, that is, the bubbling type. Part of its event model is adopted by the DOM standard. This is also good for developers. Only by using the
DOM standard, IE shares it. Event handling methods can be effective across browsers.
The DOM (Document Object Model) structure is a tree structure. When an HTML element generates an event, the event will be pressed between the element node and the root node. Propagated in a specific order, all nodes along the path will receive the event. This propagation process can be called DOM event flow.
There are two types of event sequences: event capturing and event bubbling.
Bubbling event (Event Bubbling)
This is the implementation of the event model by IE browser, and it is also the easiest to understand, at least I think it is more realistic. Bubbling, as the name suggests, events bubble up like bubbles in water until they reach the top. From the perspective of the DOM tree structure, events are passed from leaf nodes up to the root node along the ancestor nodes; from the browser interface view HTML element arrangement level, events are passed from the most certain target element with a subordinate relationship to The most uncertain target element. Bubbling technology. The basic idea of bubbling events. Events start from a specific event target to the most uncertain event target.
Capturing events (Event Capturing)
Netscape's implementation is just the opposite of the bubbling type, starting from the topmost element of the DOM tree to the most precise element. This event model is a bit confusing for developers (at least me...) because intuitively The understanding should be like the bubbling type, and event delivery should start from the most certain element, that is, the event generating element.
DOM standard event model
We have explained and compared the above two different event models. The DOM standard supports two event models at the same time, namely capturing events and bubbling events. However, capturing events occur first. Both event streams will trigger all objects in the DOM, starting from the document object and ending with the document object (most standards-compliant browsers will continue to capture/bubble events to the window object).
As shown in the figure: first is the capturing event delivery, and then is the bubbling delivery. Therefore, if a processing function registers both the capture event listening and the bubbling event Bubble event listener, then it will be called twice in the DOM event model.
The most unique feature of the DOM standard event model is that text nodes will also trigger events (not in IE).
Event Transmission
In order to better explain the event flow principle in the DOM standard, we put it in the "Event Transmission" summary to be more specific explanation of.
Obviously, if a click event listener is added to a hyperlink, the event listener will be executed when the link is clicked. But if the event listener is assigned to the p element containing the link or the document node at the top of the DOM tree, then clicking the link will also trigger the event listener. This is because events don't just affect the element they trigger on, they affect all elements along the DOM structure. This is known as event forwarding.
The W3C event model clearly points out the principle of event forwarding. Event delivery can be divided into 3 stages.
As shown in the figure: Standard event transfer mode
(1). In the event capturing (Capturing) phase, the event will be transferred downward along the DOM tree , each ancestor node of the target node, until the target node. For example, if the user clicks a hyperlink, the click event will be transferred from the document node to the html element, body element, and p element containing the link.
During this process, the browser will detect the capture event listener for the event and run the event listener.
(2). In the target phase, after the browser finds the event listener that has been assigned to the target event, it will run the event listener. The target node is the DOM node that triggered the event. For example, if the user clicks a hyperlink, that link is the target node (in this case, the target node is actually the text node within the hyperlink).
(3). In the bubbling stage, the event will be transferred upward along the DOM tree, and the ancestor nodes of the target element will be visited one by one again to the document node. every step of the way. Browsers will detect event listeners that are not capture event listeners and execute them.
Not all events will go through the bubbling phase
All events will go through the capture phase and the target phase, but some events will skip the bubbling phase. For example, the focus event that causes the element to gain input focus and the blur event that causes the element to lose input focus will not bubble.
Event handle
Event handle (also known as event processing function, DOM calls it event listening function), the function called in response to an event is called the event processing function
. Each event corresponds to an event handler. When the program is executed, the corresponding function or statement is assigned to the event handler. When the event occurs, the browser executes the specified function or statement, thereby realizing the integration of web page content and user operations. Interaction. When the browser detects that an event occurs, it searches to see if the event handler corresponding to the event has been assigned a value. If so, it executes the event handler.
We believe that the function that responds to the click event is the onclick event processing function. Previously, event handlers were assigned in two ways: in JavaScript or in HTML.
If you assign an event handling function in JavaScript, you need to first obtain a reference to the object to be processed, and then assign the function to the corresponding event handling function attribute. Please see a simple example:
1 var link=document.getElementById("mylink");2 link.onclick=function(){3 alert("I was clicked !");4 };
From the examples we saw, we found that using event handlers is easy, but the event handler function name must be in lowercase, and the event handler can only be assigned after the element is loaded. Give the element, otherwise there will be exceptions.
Regarding document loading technology, please see the article "Multiple Solutions for Window.onload Loading".
If the event handler is allocated in HTML, just set the event handler function directly through the HTML attribute, and include the appropriate script as the attribute value, for example:
<a href="/" onclick="JavaScript code here">......</a>
This JavaScript code is similar to directly assigning CSS attributes to elements through the HTML style attribute. This makes the code look messy and violates the principle of separating code that implements dynamic behavior from code that displays the static content of the document. Since 1998, this way of writing has become obsolete.
The advantages and disadvantages of this traditional event binding technology are obvious:
*Simple and convenient, directly write the code block of the processing function in HTML, and assign the corresponding event attributes to the element in JS Just assign a value.
*A method supported by both IE and DOM standards. It is called during the event bubbling process in both IE and DOM standards.
*You can directly use this to refer to the element that registered the event in the processing function block. This refers to the current element.
*If you want to register multiple listeners for an element, you cannot use this method.
Event Listener
In addition to the simple event handlers introduced earlier, most browsers now have some built-in more advanced event handling methods, that is, event listeners. The processing method is not limited by the fact that an element can only be bound to one event handler.
We already know that the biggest difference between event handlers and event listeners is that when using event handlers, only one event handler can be plugged in at a time, but for event listeners, multiple event handlers can be plugged in at a time.
Event listener under IE:
IE提供的却是一种自有的,完全不同的甚至存在BUG的事件监听器,因此如果要让脚本在本浏览器中正常运行的话,就必须使用IE所支持的事件监听器。另外,Safari 浏览器中的事件监听器有时也存在一点不同。
在IE中,每个元素和window对象都有两个方法:attachEvent方法和detachEvent方法。
1 element.attachEvent("onevent",eventListener);
此方法的意思是在IE中要想给一个元素的事件附加事件处理函数,必须调用attachEvent方法才能创建一个事件监听器。attachEvent方法允许外界注册该元素多个事件监听器。
attachEvent接受两个参数。第一个参数是事件类型名,第二个参数eventListener是回调处理函数。这里得说明一下,有个经常会出错的地方,IE下利用attachEvent注册的处理函数调用时this指向不再是先前注册事件的元素,这时的this为window对象。还有一点是此方法的事件类型名称必须加上一个”on”的前缀(如onclick)。
1 element.attachEvent("onevent",eventListener);
要想移除先前元素注册的事件监听器,可以使用detachEvent方法进行删除,参数相同。
DOM标准下的事件监听器:
在支持W3C标准事件监听器的浏览器中,对每个支持事件的对象都可以使用addEventListener方法。该方法既支持注册冒泡型事件处理,又支持捕获型事件处理。所以与IE浏览器中注册元素事件监听器方式有所不同的。
1 //标准语法 2 element.addEventListener('event', eventListener, useCapture);3 //默认4 element.addEventListener('event', eventListener, false);
addEventListener方法接受三个参数。第一个参数是事件类型名,值得注意的是,这里事件类型名称与IE的不同,事件类型名是没’on’开头的;第二个参数eventListener是回调处理函数(即监听器函数);第三个参数注明该处理回调函数是在事件传递过程中的捕获阶段被调用还是冒泡阶段被调用 ,通常此参数通常会设置为false(为false时是冒泡),那么,如果将其值设置为true,那就创建一个捕捉事件监听器。
移除已注册的事件监听器调用element的removeEventListener方法即可,参数相同。
1 //标准语法 2 element.removeEventListener('event', eventListener, useCapture);3 //默认4 element.removeEventListener('event', eventListener, false);
通过addEventListener方法添加的事件处理函数,必须使用removeEventListener方法才能删除,而且要求参数与添加事件处理函数时addEventListener方法的参数完全一致(包括useCapture参数),否则将不能成功删除事件处理函数。
跨浏览器的注册与移除元素事件监听器方案
我们现在已经知道,对于支持addEventListener方法的浏览器,只要需要事件监听器脚本就都需要调用addEventListener方法;而对于不支持该方法的IE浏览器,使用事件监听器时则需要调用attachEvent方法。要确保浏览器使用正确的方法其实并不困难,只需要通过一个if-else语句来检测当前浏览器中是否存在addEventListener方法或attachEvent方法即可。
这样的方式就可以实现一个跨浏览器的注册与移除元素事件监听器方案:
1 var EventUtil = {
2 //注册
3 addHandler: function(element, type, handler){
4 if (element.addEventListener){
5 element.addEventListener(type, handler, false);
6 } else if (element.attachEvent){
7 element.attachEvent("on" + type, handler);
8 } else {
9 element["on" + type] = handler;
10 }
11 },
12 //移除注册
13 removeHandler: function(element, type, handler){
14 if (element.removeEventListener){
15 element.removeEventListener(type, handler, false);
16 } else if (element.detachEvent){
17 element.detachEvent("on" + type, handler);
18 } else {
19 element["on" + type] = null;
20 }
21 }
22 };
Event Object Reference
In order to better handle events, you can take different actions based on the specific properties of the event that occurred.
Like the event model, IE handles objects differently from other browsers: IE uses a global event object called event to handle objects (it can be found in the global variable window.event), while all other browsers The method recommended by W3C is to use independent parameter passing containing event objects.
When implementing such a function across browsers, the most common problem is to obtain a reference to the event itself and obtain a reference to the target element of the event.
The following code will solve this problem for you:
1 var EventUtil ={
2 getEvent: function(event){
3 return event ? event : window .event;
4 },
5 getTarget: function(event){
6 return event.target || event.srcElement;
7 }
8 };
"Stop event bubbling" and "Block the browser's default behavior", these two concepts are very important, and they are very useful for complex application processing.
1. Stop event bubbling
Stop event bubbling means to stop the further delivery of bubbling events (cancel event delivery, not just stop the bubbling type common to IE and DOM standards) event, we can also stop supporting DOM standard browser capture events, using the topPropagation() method). For example, in the bubbling event delivery in the figure above, after body processing stops event delivery, the event listener of the upper document will no longer receive notifications and will no longer be processed.
2. The default behavior of blocking events
The default behavior of stopping events means that usually the browser will execute the default action associated with the event after the event is delivered and processed (if there is such a Actions). For example, if the input type attribute in the form is "submit", the browser will automatically submit the form after the event is propagated after clicking. For another example, after the keydown event of the input element occurs and is processed, the browser will automatically append the characters typed by the user to the value of the input element by default.
How to stop event bubbling:
In IE, just set cancelBubble of the event object to true.
1 function someHandle() {
2 window.event.cancelBubble = true;
3}
DOM standard can be done by calling the stopPropagation() method of the event object.
1 function someHandle(event) {
2 event.stopPropagation();
3 }
Therefore, the cross-browser stop event delivery method is:
1 function someHandle(event) {
2 event = event || window.event;
3 if(event.stopPropagation){
4 event.stopPropagation();
5 } else {
6 event.cancelBubble = true;
7 }
8 }
How to prevent the default behavior of events
Just like the difference between event models and event objects Likewise, the default behavior of blocking events is different in IE and all other browsers.
Under IE, just set the returnValue of the event object to false.
1 function someHandle() {
2 window.event.returnValue = false;
3}
DOM standard can be achieved by calling the preventDefault() method of the event object.
1 function someHandle(event) {
2 event.preventDefault();
3 }
Therefore, the default processing method after the cross-browser cancellation event is passed is :
1 function someHandle(event) {
2 event = event || window.event;
3 if(event.preventDefault){
4 event.preventDefault();
5 }else{
6 event.returnValue = false;
7 }
8 }
Complete event handling compatibility function
1 var EventUtil = {
2 addHandler: function(element, type, handler){
3 if (element.addEventListener){
4 element.addEventListener(type, handler, false);
5 } else if (element.attachEvent){
6 element.attachEvent("on" + type, handler);
7 } else {
8 element["on" + type] = handler;
9 }
10 },
11 removeHandler: function(element, type, handler){
12 if (element.removeEventListener){
13 element.removeEventListener(type, handler, false);
14 } else if (element.detachEvent){
15 element.detachEvent("on" + type, handler);
16 } else {
17 element["on" + type] = null;
18 }
19 },
20 getEvent: function(event){
21 return event ? event : window.event;
22 },
23 getTarget: function(event){
24 return event.target || event.srcElement;
25 },
26 preventDefault: function(event){
27 if (event.preventDefault){
28 event.preventDefault();
29 } else {
30 event.returnValue = false;
31 }
32 },
33 stopPropagation: function(event){
34 if (event.stopPropagation){
35 event.stopPropagation();
36 } else {
37 event.cancelBubble = true;
38 }
39 };
标准事件模型为我们提供了两种方案,可能很多朋友分不清这两种不同模型有啥好处,为什么不只采取一种模型。
这里抛开IE浏览器讨论(IE只有一种,没法选择)什么情况下适合哪种事件模型。
1. 捕获型应用场合
捕获型事件传递由最不精确的祖先元素一直到最精确的事件源元素,传递方式与操作系统中的全局快捷键与应用程序快捷键相似。当一个系统组合键发生时,如果注册了系统全局快捷键监听器,该事件就先被操作系统层捕获,全局监听器就先于应用程序快捷键监听器得到通知,也就是全局的先获得控制权,它有权阻止事件的进一步传递。所以捕获型事件模型适用于作全局范围内的监听,这里的全局是相对的全局,相对于某个顶层结点与该结点所有子孙结点形成的集合范围。
例如你想作全局的点击事件监听,相对于document结点与document下所有的子结点,在某个条件下要求所有的子结点点击无效,这种情况下冒泡模型就解决不了了,而捕获型却非常适合,可以在最顶层结点添加捕获型事件监听器,伪码如下:
1 function globalClickListener(event) {
2 if(canEventPass == false) {
3 //取消事件进一步向子结点传递和冒泡传递
4 event.stopPropagation();
5 //取消浏览器事件后的默认执行
6 event.preventDefault();
7 }
8 }
这样一来,当canEventPass条件为假时,document下所有的子结点click注册事件都不会被浏览器处理。
2. 冒泡型的应用场合
It can be said that we usually use the bubbling event model, because IE only supports this model. Let’s talk about it again. Proper use of this model can improve script performance. In some frequently triggered events of elements, such as onmousemove, onmouseover, and onmouseout, if it is clear that there is no need to pass the event further after processing, then you can boldly cancel it. In addition, if the processing of the child node event listener will have a negative impact on the processing of the parent
layer listener, further upward transmission of events should also be prohibited in the child node listener to eliminate the impact.
Finally combine the following HTML code for analysis:
1
3
4
5
After HTML is run, click on the red area. This is the innermost p. According to the above Explain that whether it is DOM standard or IE, the listening processing function written directly in HTML is called when the event is bubbling and passed upward from the innermost layer, so
current is event_source
current will appear one after another. is p2
current is p1
current is p0
current is body
Add the following fragment:
1 var p2 = document.getElementById('p2');
2 EventUtil.addHandler(p2, 'click', function(event){
3 event = EventUtil.getEvent(event);
4 EventUtil.stopPropagation(event);
5}, false) ;
current is event_sourcecurrent is p2
When the red area is clicked, according to the above description, during the bubble processing, the event is stopped after being passed to p2, so the elements above p2 The notification cannot be received, so it will appear one after another:
In a browser that supports the DOM standard, add the following code:
1 document.body.addEventListener('click', function(event) {
2 event.stopPropagation();
3 }, true);
The listening function in the above code is called when the capture type is passed, so after clicking on the red area, although the event The source is the element with the ID event_source, but the capture type is passed. Starting from the top level, the body node listening function is called first, and the event is canceled and passed further down, so only current is body will appear.
Related recommendations:
Detailed explanation of the event processing mechanism in node.js
javascript browser compatibility event processing mechanism
The above is the detailed content of Analysis of JavaScript event handling mechanism. For more information, please follow other related articles on the PHP Chinese website!