JS basic-event model (event & event flow & custom event & event bubbling/agent)

1. Events and event flow

An event is the moment of interaction with the browser or document, such as clicking a button, filling in a form, etc. It is a bridge between JS and HTML.
The DOM is a tree structure. If events are bound to both parent and child nodes at the same time, when the child node is triggered, how is the order of the two events determined? This involves the concept of event flow, which describes the acceptance in the page The sequence of events.

There are two types of event streams:

  • Event Capturing: It is a way of spreading from bottom to top. The event is initially received by the most specific element (the node with the deepest nesting level in the document, that is, the child node at the lowest level of the DOM), and then gradually propagates upward to the least specific node, which is the parent at the highest level in the DOM. node.
  • Event Bubbling: The opposite of event bubbling. At the beginning of the event, the less specific node accepts the event first, and the most specific node accepts the event last.

Sequence:
capture phase-target phase-bubbling phase
At the same time binding event capture and event bubbling, event capture will be performed first.

Second, the event model

  • DOM0 is an event written directly in html through onclick;
  • DOM2 is an event bound by addEventListener, and DOM2 events under IE are bound by attachEvent;
  • DOM3 is some new events.

1. DOM0 level model

Also known as the original event model, in this model, events will not spread, that is, there is no concept of event flow. Event binding monitoring function is relatively simple, there are two ways:

  1. Direct binding in HTML code:
<input type="button" onclick="fun()">
  1. Specify attribute values ​​through JS code:
var btn = document.getElementById('.btn');
btn.onclick = fun;

Remove the monitoring function:

btn.onclick = null;

In this way, all browsers are compatible, but there is no separation between logic and display.

2.IE event model

There are two processes in the IE event model:

  • Event processing phase (target phase). When the event reaches the target element, the target element's listener function is triggered.

  • Event bubbling phase (bubbling phase). Events bubble up from the target element to the document, and check whether the passed node is bound to an event listener function, and execute it if there is one.

The way to bind the event listener function is as follows:

attachEvent(eventType, handler)

The way to remove the event listener function is as follows:

detachEvent(eventType, handler)

Parameter Description:

  • eventType specifies the event type (note the addition of on)

  • handler is an event processing function
    example:

var btn = document.getElementById('.btn');
btn.attachEvent(‘onclick’, showMessage);
btn.detachEvent(‘onclick’, showMessage);

3. DOM2 level model

It belongs to the W3C standard model, and modern browsers (other than IE6-8) support this model. In this event model, there are three processes for an event:

  • Event capture phase (capturing phase). The event is propagated from the document all the way down to the target element, and the passing nodes are checked in turn whether the event listener function is bound, and if there is, it will be executed.

  • Event processing phase (target phase). When the event reaches the target element, the target element's listener function is triggered.

  • Event bubbling phase (bubbling phase). Events bubble up from the target element to the document, and check whether the passed node is bound to an event listener function, and execute it if there is one.

The way to bind the event listener function is as follows:

addEventListener(eventType, handler, useCapture)

The way to remove the event listener function is as follows:

removeEventListener(eventType, handler, useCapture)

Parameter Description:

  • eventType specifies the event type (do not add on)
  • handler is the event processing function
  • useCapture is a boolean used to specify whether to process in the capture phase, and it is generally set to false to be consistent with IE browser. (Default false bubbling)

example:

var btn = document.getElementById('.btn');
btn.addEventListener(‘click’, showMessage, false);
btn.removeEventListener(‘click’, showMessage, false);

4. DOM3 level event handling method

There are many events that may occur in the DOM browser. There are many different event types with different information. DOM3 level events stipulate the following types of events

  • UI events are triggered when the user interacts with elements on the page
  • Focus events are triggered when an element gains or loses focus
  • The mouse event is triggered when the user performs an operation on the page with the mouse
  • The wheel event is triggered when the mouse wheel or similar device is used
  • Text event is triggered when text is entered in the document
  • Keyboard events are triggered when the user performs an operation on the page through the keyboard
  • The synthesis event is triggered when a character is entered for the IMEInput Method Editor input method editor
  • Change event is triggered when the underlying Dom structure changes

The DOM3 level event module redefines these events on the basis of DOM2 level events and adds some new events. Major browsers, including IE9, support DOM2 level events and IE9 also supports DOM3 level events.

Events in the DOM simulate custom events

The DOM3 level also defines custom events. Custom events are not triggered natively by the DOM. Its purpose is to allow developers to create their own events. The custom event to be created can be created by createEvent("CustomEvent");

The returned object has an initCustomEvent method that receives the following four parameters.

  • Customize the type of event triggered by the type string. For example "keyDown" "selectedChange";

  • The bubble boolean indicates whether the event should bubble

  • cancelable (boolean) indicates whether the event can be canceled

  • Any value of the detail object is stored in the detail attribute of the event object

This will be described in detail later.

Third, the event object

When an event is triggered, an event object (Event Object) is created, which contains properties or methods related to the event. This object will be passed to the listener function as the first parameter.

Common attributes of event objects in the DOM event model:

  • type is used to get the event type
  • target to get the event target
  • stopPropagation() prevents the event from bubbling
  • preventDefault() prevents the default behavior of the event

Common attributes of event objects in the IE event model:

  • type is used to get the event type
  • srcElement gets the event target
  • cancelBubble prevents the event from bubbling
  • returnValue prevents the default behavior of the event

Four, event binding and cancellation

1. Event binding

1.1 Object.on event name = event handling function

Disadvantage: If you bind multiple events, the previous event will be overwritten by the following event

document.getElementById("btn").onclick = function () {
        console.log("第一");
    };

1.2. Object. addEventListener ("the event name without on", event handler, false)

Explanation: The third parameter is explained in the event phase of this article, false: bubbling; true: capture

Advantages: multiple events can be bound

Disadvantages: Google and Firefox support, IE8 does not support

document.getElementById("btn").addEventListener("click", function () {
        console.log("第一");
    }, false);
    //false冒泡阶段(默认),true捕获阶段

3. Object.attachEvent ("on event name", event processing function);

Advantages: multiple events can be bound

Disadvantages: Google and Firefox do not support, IE8 supports

document.getElementById("btn").attachEvent("onclik", function () {
        console.log("第一");
    });

2. Unbind

How to bind the event, you should use the corresponding way to unbind the event
1. Unbind the event

对象.on事件名字=事件处理函数--->绑定事件  
对象.on事件名字=null;  

2. Unbinding incident

对象.addEventListener("没有on的事件类型",命名函数,false);---绑定事件  
对象.removeEventListener("没有on的事件类型",函数名字,false);  

3. Unbinding incident

对象.attachEvent("on事件类型",命名函数);---绑定事件  
对象.detachEvent("on事件类型",函数名字);  

五、Event Wrapper

Due to the differences in event models and Event objects, in order to achieve compatibility with various browsers, we can add an Event Wrapper, which should provide a consistent event operation interface for each browser.

var eventUtils={
     // 添加句柄
     addHandler:function(element,type,handler){
       if(element.addEventListener){
         element.addEventListener(type,handler,false);
       }else if(element.attachEvent){
         element.attachEvent('on'+type,handler);
       }else{
         element['on'+type]=handler;
       }
     },
     // 删除句柄
     removeHandler:function(element,type,handler){
       if(element.removeEventListener){
         element.removeEventListener(type,handler,false);
       }else if(element.detachEvent){
         element.detachEvent('on'+type,handler);
       }else{
         element['on'+type]=null;
       }
     },
    //获取事件对象
    //IE模型中event是一个全局唯一的对象绑定在window对象上
    getEvent:function(event){
       return event?event:window.event;
    },
    //获取类型
    getType:function(event){
     return event.type;
    },
    getElement:function(event){
     return event.target || event.srcElement;
    },
    //阻止默认事件
    preventDefault:function(event){
     if(event.preventDefault){
      event.preventDefault();
     }else{
      event.returnValue=false;
     }
    },
    //阻止冒泡
   stopPropagation:function(event){
   if(event.stopPropagation){
     event.stopPropagation();
   }else{
     event.cancelBubble=true;
    }
   }
  }

Six, custom events

There are many built-in events in JS, such as click, mouseover, etc., but the built-in events are limited after all. Sometimes we want to define some events ourselves, such as three-click, threeclick. How to implement custom events?

  1. First, create an event. The following methods can be used:
var event = new Event('threeclick', {"bubbles":true, "cancelable":false});
  • bubbles indicates whether the event is bubbling.
  • cancelable indicates whether the event can be canceled.
  1. Then we need to register a listener function for the event:
target.addEventListener('threeclick', hello, false);
  1. Finally, we need to trigger the event at the right time, we can use the dispatchEvent function. This method triggers a specified event on the current node, thereby triggering the execution of the monitoring function. This method returns a boolean value. As long as a listener function calls Event.preventDefault(), it returns false, otherwise it returns true.
target.dispatchEvent(event);

Seven, JQuery Event model

One of the main problems solved by JQuery is the compatibility of browsers. It has its own event model implementation. It mainly has the following characteristics:

  • Redefine the JQuery.Event object, unify the event attributes and methods, and unify the event model
  • You can add multiple event handlers to one event type, and you can add event handlers of multiple event types at once
  • Support custom events (event namespace)
  • Provides toggle, hover combination events
  • Provide one, live-die, delegate-undelegate
  • Provides a unified event encapsulation, binding, execution, and destruction mechanism
  • $(document).ready();

8. JS event model-observer model

Observer mode is also called Publish/Subscribe mode, which allows multiple observer objects to monitor a certain topic object at the same time. When the state of this topic object changes, it will notify all subscribers so that they can react. .
The event model of JS is a manifestation of the observer mode. When the corresponding event is triggered, all the monitoring functions that monitor the event will be called.

Code for an observer pattern implemented in JS:

var events = (function() {
  var topics = {};

  return {
    publish: function(topic, info) {
      console.log('publish a topic:' + topic);
      if (topics.hasOwnProperty(topic)) {
        topics[topic].forEach(function(handler) {
          handler(info ? info : {});
        })
      }
    },
    subscribe: function(topic, handler) {
      console.log('subscribe an topic:' + topic);
      if (!topics.hasOwnProperty(topic)) {
        topics[topic] = [];
      }

      topics[topic].push(handler);
    },
    remove: function(topic, handler) {
      if (!topics.hasOwnProperty(topic)) {
        return;
      }

      var handlerIndex = -1;
      topics[topic].forEach(function(element, index) {
        if (element === handler) {
          handlerIndex = index;
        }
      });

      if (handlerIndex >= 0) {
        topics[topic].splice(handlerIndex, 1);
      }
    },
    removeAll: function(topic) {
      console.log('remove all the handler on the topic:' + topic);
      if (topics.hasOwnProperty(topic)) {
        topics[topic].length = 0;
      }
    }
  }
})();

use:

//主题监听函数
var handler = function(info) {
    console.log(info);
}
//订阅hello主题
events.subscribe('hello', handler);

//发布hello主题
events.publish('hello', 'hello world');

Nine, code example (general event binding & event bubbling & proxy)

1. General Event Binding

//原本的
var btn = document.getElementById('btn1');
btn.addEventListener('click',function(event){
    console.log('clicked');
})

//封装的    如addEventListener 就不用重复写,不然太长了影响压缩,占用带宽
function bindEvent(elem,type,fn){
    elem.addEventListener(type,fn);
}
//使用
var a = document.getElementById('link1');
bindEvent(a,'click',function(e){
    e.preventDefault(); //阻止默认行为,如a标签跳转
    alert(clicked);
})

Improve the function of general binding events (add proxy)

function bindEvent(elem,type,selector,fn){
    if(fn == null){//没传入代理
        fn = selector;x
        selector = null;
    }
    elem.addEventListener(type,function(e){
        var target;
        if(selector){//如果存在代理
        target = e.target;  //target事件属性可返回事件的目标节点(触发该事件的节点)
        if(target.matches(selector)){ //判断是否满足这个选择器
            fn.call(target,e)
        }
        }else{
            fn(e);
        }
    })
}


//使用代理  好处:代码简洁,减少浏览器内存占用
var div1 = document.getElementById('div1');
bindEvent(div1,'click','a',function(e){
    console.log(this.innerHTML); //此处的this是a
});

2. Event bubbling

Click p1 to activate, click other to cancel, use bubbling, no need to add a canceled click event next to it

 <body>
        <div id="div1">
            <p id="p1">激活</p>
             <p id="p2">取消</p>
              <p id="p3">取消</p>
               <p id="p4">取消</p>
        </div>
        <div id="div2">
            <p id="p5">取消</p>
             <p id="p6">取消</p>
        </div>
    </body>


    var p1 = document.getElementById('p1');
    var body = document.body;
    bindEvent(p1,'click',function(e){
        e.stopPropatation();  // 阻止冒泡,就不会再触发body上的取消事件了;
        alert('激活');
    })
    bindEvent(body,'click',function(e){
        alert('取消')
    })

     //封装的    如addEventListener 就不用重复写,不然太长了影响压缩,占用带宽
        function bindEvent(elem,type,fn){
            elem.addEventListener(type,fn);
        }

3. Agency

 <div id="div1">
       <a href="#">a1</a>
        <a href="#">a2</a>
         <a href="#">a3</a>
          <a href="#">a4</a>
          <!-- 会随时新增更多的 a标签 -->
</div>

var div1 = document.getElementById('div1');
div1.addEventListener('click',function(e){
    var target = e.target;
    if(target.nodeName === 'A'){
        alert(target.innerHTML);
    }
})

Additional node operation

  • document.getElementById();//id name, which is rarely used in actual development. The class id is usually used in the selector. Generally, it is only used at the top level and cannot rely on id too much.

  • document.getElementsByTagName();//Tag name

  • document.getElementsByClassName();//类名

  • document.getElementsByName();//name attribute value, generally not used

  • document.querySelector();//css selector pattern, returns the first element that matches the pattern, and the result is an element; if no matching element is found, null is returned

  • document.querySelectorAll()//css selector pattern, returns all elements matching the pattern, and the result is a class array

  • parentNode//Get the parent node of the selected node, the topmost node is #document

  • childNodes //Get the child nodes of the selected node

  • firstChild //Get the first child node of the selected node

  • lastChild //Get the last child node of the selected node

  • nextSibling //Get the nextSibling attribute value of the last node in the next sibling node list of the selected node is null

  • previousSibling //Get the previousSibling attribute value of the first node in the previous sibling node list of the selected node to be null

Reference: https://segmentfault.com/a/1190000006934031

Link to this article: https://blog.csdn.net/qq_39903567/article/details/115281827

Guess you like

Origin blog.csdn.net/qq_39903567/article/details/115281827