Original address:

  • JS event flow model
  • Event bubbling and blocking

JS event flow model

Event capture is propagated from outside to inside. Take the click event for example, it propagates inward from the outermost root node to the clicked node, and gradually propagates inward from the outermost node to the target node.

Event bubbling is propagated from the inside out. Again, take the click event, which starts at the clicked node and then works its way up to the highest node.

DOM0 level model

Also known as the raw event model, this approach is simpler and compatible with all browsers, but it couples the interface with logic and is less maintainable.

The instance

When you click on

with id i3, the console prints 2, 1, 0.
<body>
    <div id="i1" onclick="console.log(0)">
        <div id="i2" onclick="console.log(1)">
            <div id="i3" onclick="console.log(2)"></div>
        </div>
    </div>
</body>
Copy the code

IE Event Model

Capturing events is not supported in IE8 and earlier versions, and the IE event model consists of two processes:

Target Phase, where an event reaches the target element and triggers a listening event for the target element.

The Bubbling Phase event executes the node bound events that pass through, from the target element bubbling to the document.

DOM2 level model

DOM2 event model is a standard model developed by W3C, which supports capture event and bubble event. The processing stage of call event is capture, target and bubble.

The instance

When

with id i3 is clicked, the browser pops up 0, 1, 3, 2. The third argument to the addEventListener method declares whether the bound event is captured or bubbling. The default is false, that is, bubbling.

<body>
    <div id="i1" onclick="console.log(0)">
        <div id="i2" onclick="console.log(1)">
            <div id="i3" onclick="console.log(2)"></div>
        </div>
    </div>
<script type="text/javascript">
    document.addEventListener('click'.(e) = > {
        console.log(0);
    },true) 
    document.getElementById("i1").addEventListener('click'.(e) = > {
        console.log(1);
    },true) 
    document.getElementById("i2").addEventListener('click'.(e) = > {
        console.log(2);
    })  
    document.getElementById("i3").addEventListener('click'.(e) = > {
        console.log(3);
    })     
</script>
</body>
Copy the code

Document object and i1 node are bound to capture type listening events, while I2 and I3 nodes are bound to bubble type events, and the sequence of event transmission is:

window - document - html - body - i1 - i2 - i3 - i2 - i1 - body - html - document - window
Copy the code

The process from window to i3 is the capture stage, and the events bound in the process are successively executed. In this example, alert(0) and alert(1) are executed, and then the target stage i3 is reached, and the event alert(3) bound by I3 is executed. Then the stage from i3 to window is the bubble stage. The bound alert(2) is executed in the order 0, 1, 3, 2.

Pay attention to

Bind differences in the use of listening events

In DOM0, when the directly bound function is executed, the post-defined function overwrites the previously bound function. The following example only executes alert(1) without alert(0). Click () is an object event that triggers the onclick() binding method. Onclick () is an object property that is bound to a function that executes after the click() event is triggered.

<body>
    <div id="i1"></div>
<script type="text/javascript">
    document.getElementById("i1").onclick = function(){
        alert(0); / / are covered
    }
    document.getElementById("i1").onclick = function(){
        alert(1); / / execution
    }
</script>
</body>

Copy the code

The addEventListener can bind multiple functions to an event without adding on, and it can also receive a third parameter, useCapture, to determine whether the capture or bubble phase of the binding is executed at the time of the event.

<script type="text/javascript">
    document.getElementById("i1").addEventListener('click'.(e) = > {
        alert(0); / / execution
    })
    document.getElementById("i1").addEventListener('click'.(e) = > {
        alert(1); / / execution
    })
</script>
Copy the code

AttachEvent can bind multiple functions to an event, requiring on. It only supports bubbling, so there is no third argument.

<script type="text/javascript">
    document.getElementById("i1").attachEvent('onclick'.function(e){
        alert(0); / / execution
    })
    document.getElementById("i1").attachEvent('onclick'.function(e){
        alert(1); / / execution
    })
</script>
Copy the code

Event bubbling and blocking

When an element receives an event, it passes the event to its parent, all the way to the window. Of course, it propagates the event, and the bound function does not propagate. If the parent does not bind the event function, it does not do anything if it passes the event, but the event does pass.

Events bubble because the event source itself may not have the ability to handle events, that is, the functions that handle events are not bound to the event source. It can’t handle the event itself, so it needs to be propagated so that it can reach the execution function that handles the event.

The instance

When you click on

with id i3, the browser pops up 3, 2, 1, which is the event bubble. The square is on the leaf node, and the events that operate on it bubble up to the root node.
<body>
    <div id="i1">
        <div id="i2">
            <div id="i3"></div>
        </div>
    </div>
<script type="text/javascript">
    document.getElementById("i1").addEventListener('click'.(e) = > {
        alert(1);
    }) 
    document.getElementById("i2").addEventListener('click'.(e) = > {
        alert(2);
    })  
    document.getElementById("i3").addEventListener('click'.(e) = > {
        alert(3);
    })     
</script>
</body>
Copy the code

Application scenarios

For example, we have 10

  • tags, and each tag has a UID to determine the difference between user clicks. Using bubble, there is no need to bind click events for each
  • , which can be called event delegate.
  • <body>
        <ul id="u1">
            <li uid="0">0</li>
            <li uid="1">1</li>
            <li uid="2">2</li>
            <li uid="3">3</li>
            <li uid="4">4</li>
            <li uid="5">5</li>
            <li uid="6">6</li>
            <li uid="Seven">7</li>
            <li uid="8">8</li>
            <li uid="9">9</li>
        </ul>
    <script type="text/javascript">
        document.getElementById("u1").addEventListener('click'.(e) = > {
            alert(e.srcElement.getAttribute('uid'));
        })    
    </script>
    </body>
    Copy the code

    To prevent a bubble

    Sometimes we don’t want event bubbling and to perform any node binding event, this time will need to stop the event bubbling, w3c is e.s topPropagation (), IE is to use window. The event. The cancelBubble = true; .

    If using the Vue framework, @click.stop=””

    Pay attention to

    • Not all events can bubble up. The following events do not bubble:blur,focus,load,unload.
    • The event resolution may vary from browser to browser. Some do not support the capture solution, while most browsers default to the bubble solution.
    • Preventing bubbling does not prevent object default behavior, for examplesubmitWhen the button is clicked, it will submit the form datae.preventDefault();Prevent default behavior,IEIt iswindow.event.returnValue = false;.