JS programming is often exposed to DOM events, although just events, but in historical reasons, it is complex enough, but also powerful enough, due to their previous always on the DOM events of some concepts unclear, so here to make a summary
DOM levels and DOM events
We often hear about DOM0 level events, DOM1 level events, and DOM2 level event processing, but DOM0, DOM1, DOM2 and DOM levels are closely related.
At the beginning, browsers such as IE4 and Netscape implemented their own DOM apis. There was no unified standard, which was a headache for developers and users. Therefore, in 1998, THE W3C developed DOM Level 1 standard by integrating the existing apis of various browsers. DOM1 level is concise and consists of two modules: DOM Core and DOM HTML, where event-related information is contained as methods in the DOM element, as described in the W3C chapter.
The target of DOM2 level is much broader, and a number of new modules are introduced, including DOM Events, that is, in DOM2, Events are taken as a module alone, and the DOM1 level event part is greatly upgraded. It is no longer simply telling us what Events can be used, but making the event standard more detailed. Such as new event flow, event capture, event bubbling, event cancellation mechanisms and specifications.
DOM Level 3 does not make any changes to Events (probably because DOM Events are considered mature enough), so we know that we still use the DOM Level 2 event standard.
The DOM API has three standards for DOM1, DOM2, and DOM3. The corresponding parts of each standard are called DOM1 event processing and DOM2 event processing. So the standard starts with DOM Level 1, what do we mean by DOM0? We can say that this is just an accepted way of saying that event processing before there is a fact standard is called DOM0 event processing.
Tips
DOM1 is generally considered the same event handling as DOM0, since DOM1 is only a standard for previous DOM apis.
Event handler
An event handler is a function that responds to an event, and event handlers in the DOM come in a variety of ways, roughly divided into the following three types.
- HTML event handler
- DOM0 level event handler
- Dom2-level event handler
HTML event handler
<button onclick="alert(hello world!) "></hello>
Copy the code
This is the HTML event handler that writes the event function directly to an attribute of an HTML element. The part in the double quotes is the code that executes after the event is triggered. It is actually called by the JS engine by eval(), so it is globally scoped.
One of the obvious disadvantages of such event handling is that when JS code is too complex, it is not appropriate to unload large chunks of JS code into HTML, hence the following:
<button onclick="doSomething()"></hello>
Copy the code
This solves the problem of too long nested code, but introduces another problem, namely the time lag problem — if the user clicks on the interface as soon as it appears and the JS is not yet loaded, an error will be reported.
In addition, it is important to note that this way of writing, a function change may require both JS and HTML changes, which seriously violates the principle of light coupling. In summary, we have DOM0 level event handling.
DOM0 level event processing
<script>
var btn=document.getElementById("#btn");
btn.onclick=function(){
alert(hello world!)
}
</script>
Copy the code
As you can see, in this way you can put all the event handlers in JS, and here the event handlers are local scoped as methods of the BTN object.
But now, I still have the problem that if I add two handlers to the element’s click event, it won’t work for me, and even if I don’t need more than one handler, I don’t want to add events unless I’m pretty sure, This part is not covered when someone else writes code (because you might accidentally overwrite the handler that someone else previously added to the event on this element).
Dom2-level event handler (IE not supported)
After further specification, with dom2-level event handlers, we can add multiple handlers to the same event for an element with code like the following
var btn=document.getElementById("#btn");
btn.addEventListener("click".function(){
alert(hello world!)
})
btn.addEventListener("click".function(){
alert(hello world2!)
})
</script>
Copy the code
It is possible to bind multiple event handlers through the DOM2 level addEventListener method, but it is important to note that the same event and event flow mechanism will trigger the same method only once, that is, the same method will be overwritten. Wait, what is the flow of events here?
Event flow mechanism
funcgrand(),funcparent(),funcchild()
, first to analyze the intuitive feelings happened in son elements on click event, so you should trigger funcchild (), but carefully wanted this is wrong, because the son element itself is part of a father even grandpa element, so it is not equivalent to also click event happened on the elements of his father and grandfather? The answer is yes, in this case all three elements are bound to functions corresponding to events that are fired by the browser, so the question arises again. Since all three functions are fired, in what order should they be fired, from top to bottom or from bottom to top?
This problem is also known as event flow, which is the order in which elements receive events from the page and in which events are propagated across the page.
W3C has given us an answer to this question, is can, either from top to bottom in turn trigger, and can trigger from bottom to top, a specific order depending on our own (are support these two approaches in order to compatible with the realization of the browser before, because early event propagation direction is from top to bottom, IE and Netscape is from the bottom).
Event capture and event bubbling
In fact, the addEventListener we mentioned earlier has a third parameter, which can be true or false. When the third parameter is true, it binds events from the capture phase, where events are fired from the top down, and when the third parameter is false, it binds events from the bubble phase, where events are fired from the bottom up.
The W3C says that when an event occurs, the window is notified first, then the Document, and then the bottom up until the lowest element is known to be fired (the target element, usually the value of event.target). This process is called capture. The event then bubbles from the target element down to the window layer by layer, a process known as bubbling.
Therefore, capture is performed before bubbling
Tips
As capture and event bubbling mentioned, events program may be performed in two stages, namely capture and bubbling, added two when an event handler, a true specifies the parameters, the false, a specified parameters, they will be executed, and the first parameter to true, because is the capture phase comes first.
The exception is that if the event function is added to the target element itself, as in the previous example, two click event functions are bound to the son element, one with a third argument of true and one with a third argument of false, their actual execution order is not controlled by the third argument. It is simply related to the order in which events are added (addEventListener is executed first), which may be related to being in the target stage (target stage and capture stage and bubble stage are called the three phases, so the capture and bubble ideas should be excluded in the target stage. The real order is capture -> target stage -> bubble bar?
IE event handler
For IE, before IE9, attachEvent must be used instead of the standard method addEventListener. The IE event handler has two methods attachEvent and detachEvent that are similar to dom2-level event handlers
They both accept two arguments:
-
Event handler name, such as onclick,onmounseover, note that this is the event handler name, not the event name, with the prefix on
-
Event handler functions
-
Unlike DOM2-level event handlers, they do not accept a third parameter because IE8 and earlier only support bubbling event streams (no capture phase)
Tips
In IE8, the order in which events are executed is not the order in which they were added but the reverse order in which they were added, whereas in IE6 and 7, the order in which events are executed is random, regardless of the order in which they were added.
Another disadvantage of using the attachEvent method is that the value of this becomes a reference to the window object rather than the element that triggered the event.
Cross-browser event handlers
As mentioned above, the event handler of the older IE browser is different from the standard DOM2 event handler, so in order to be compatible with the event handling of different browsers, we can use a encapsulated utility function to implement a common add and remove event.
var EventUtil={
addEventHandler: function(type,element,handler){
if(element.addEventListener){
element.addEventListener(type,handler,false);
}else if(element.attachEvent){
element.attachEvent("on"+type,element);
}else{
element["on"+type]=handler;
}
},
removeEventHandler: function(type,element,handler){
if(element.removeEventListener){
element.removeEventListener(type,handler,false);
}else if(element.detachEvent){
element.detachEvent("on"+type,element);
}else{
element["on"+type]=null; }}}Copy the code
The event object
Event objects are used to record some information about the occurrence of an event, but they are only generated when the event occurs and can only be accessed inside the event handler. After all event handlers are finished, event objects are destroyed.
The main properties of the standard Event object are:
- Bubbles Boolean value indicating whether the event is of the bubble type
- Cancelable A Boolean value indicating whether the event can cancel the default action
- CurrentTarget the currentTarget element, which is the element to which the current event handler is added
- Target The actual target element, that is, the element that actually fires the event
- Type returns the name of the current event
- EventPhase The current phase of event propagation, where 1 indicates the capture phase
The main methods of standard Event objects are as follows:
- PreventDefault () notifies the browser not to perform the default action of this event. It is usually used to prevent links from jumping, forms from submitting, etc
- In stopPropagation() bubbling phase, prevent events from bubbling upwards
Compatibility of event objects
As with event handlers, there are compatibility issues with the properties and methods of event objects.
- In IE8 and earlier versions, event handlers registered by setting properties are called without passing event objects, requiring global objects
window.event
To obtain, the solution is as follows:
function getEvent(event){
event = event || window.event
}
function hander(event){
event = getEvent(event)
...
}
Copy the code
- Prevents default event behavior
Event preventDefault() is not available in IE, but it is possible to have the event returnValue set to false as follows:
window.event.returnValue=false;
Copy the code
- To prevent a bubble
The event object in IE also has no stopPropagation() method, but cancelBubble can be set to true to prevent further propagation of the event, as follows:
window.event.cancelBubble=true;
Copy the code
Event delegation
Event delegates use event bubbles to manage all events of a certain type by specifying an event handler. With event delegates, you can control the behavior of descendant elements by adding an event handler to an ancestor element.
- Let’s start with an example of using event delegates to manage all events of a certain type.
The requirement is to add the corresponding behavior of the click event to all li under ul. Before the event delegate is used, the code looks like this:
< ul > < li > list item 1 < / li > < li > list item 2 < / li > < li > list item 3 < / li > < / ul > < script > var list = document. The getElementsByTagName ("li");
for(i=0; i<list.length; i++){ list[i].onclick=function(){
alert("I am"+e.target);
}
}
</script>
Copy the code
So far it does, and all li’s can respond to click events, but what about adding a button to add a list item? When a list item is added dynamically, the list item element is added, but the newly added node is not bound to the event (unless the element is bound to the event logic). Here we see the problem:
- Adding event bindings to all elements can result in frequent DOM manipulation of elements, and multiple elements listening for their own events, which increases browser consumption
- When you add elements dynamically to a page, you need to go through the logic of adding listening events so that the new element can respond to the event
Fortunately, we have a better solution to this problem, which is event delegation using the bubbling principle.
We only listen for the outermost element, and then do different event handling in the event handler depending on the event source, the target attribute. This way, we only need to add an event handler for one element, greatly reducing DOM access, and we don’t need to add a separate listening event for dynamically added elements. Because the element’s events bubble up to the outermost layer and are intercepted by the outermost event handler, as follows:
var ul=document.getElementById('ulList');
ul.onclick=function(e){
var e= e || window.event;
var target = e.target || e.srcElement;
if(target.nodeName.toLowerCase() === "li"){
alert("I am"+e.target); }}Copy the code
As you can see from this example, when event delegation is used, there is no need to traverse the child nodes of the element at all, just add event listeners to the parent element, and then the new child nodes can also respond appropriately to the event
- Another common example of using event delegates is to close the float layer by clicking on it. We often use event delegates to listen for clicks in the outer space of an element to close the float layer.
Tips
- Not all events can be delegated. Suitable events for event delegation are:
click mousedown mouseup keydown keyup keypresss