Home  >  Article  >  Web Front-end  >  An introduction to JavaScript’s event flow

An introduction to JavaScript’s event flow

coldplay.xixi
coldplay.xixiforward
2021-02-14 10:30:592617browse

An introduction to JavaScript’s event flow

Free learning recommendation: js video tutorial

##About JavaScript event flow

##Foreword
  • Text
  • What is an event?
    • What Is it event streaming?
    • Event bubbling vs event capturing
    • DOM event hierarchy
    • DOM0 event
    • DOM2 event
    Conclusion
Preface

Before reading this article, I suggest you take a look at the JavaScript event loop. Of course, for those who already know it No need! This article will discuss the event flow of js.

Text

We all know that when we perform certain types of operations on a web page, such as clicking, sliding, etc., some corresponding events will be triggered. We also know that the entire web page is actually parsed into a DOM tree by the browser. When a node generates an event, the event will be propagated in a certain order between the node and the root node, and all nodes passing through this propagation path will receive the event. This entire process is called

DOM event flow

.

What are events?

The interaction between js and html is actually achieved through "events". All user clicks, selections, slides, etc. on web pages are all events in the js world.

For events, when an event occurs, there must be a response. In js, the so-called response is the listener. Just like the observer pattern, the event is our subject, and when the event occurs, all listeners corresponding to the event (subject) must be notified to perform corresponding responses.

What is event flow?

Event flow describes the order in which events are received from the page. Mainly divided into the following two types:

IE's event bubbling
  • Netscape's event capture
Event bubbling vs event capture

The event flow model proposed by IE is event bubbling, that is, from bottom to top, it propagates upward step by step from the element triggered by the target, all the way to the document object.


The event flow model proposed by Netscape is event capturing. Contrary to event bubbling, it is from top to bottom, that is, it is propagated from the document object to the target object step by step.


The above is the event flow mechanism under the DOM0 standard. Later, ECMAScript further standardized the event flow in DOM2. In DOM2, the event stream contained in an event is divided into the following three stages:

Event capture stage (capture)
  1. Target stage (target)
  2. Event bubbling stage (bubble)

DOM event classification

When an event occurs on a DOM node, of course you need to do the corresponding Department, and DOM events are divided into 4 levels, as follows:


Among them, the more important ones are DOM0/DOM2, so we will focus on them below.

DOM0 event

There are two main ways to implement DOM0-level events. The first is the inline model, which directly uses the function name as the event attribute in the html tag. attribute value. As follows:

// js code// eventDOM.jsfunction btnClick() {
    console.log('Hello World')}
<!-- html code --><html>
    <head>
        <title>eventDOM demo</title>
    </head>
    <body>
        <p onclick="btnClick()" style="width: 30px; height: 30px; background-color:black"></p>
        <script type="text/javascript" src="eventDOM.js"></script>
    </body></html>

However, the inline model has obvious shortcomings, that is, it violates the W3C requirement for the separation of content (html) and behavior (js). So there is the second type, which is the script model (dynamic binding model). The specific method is to select a specific DOM node through a js script, and then add event attributes and attribute values ​​to the node. As follows:

// js code// eventDOM.jslet btn = document.getElementById('btn')let btnClick = function() {
    console.log('Hello World')}btn.onclick = btnClick
<!-- html code --><html>
    <head>
        <title>eventDOM demo</title>
    </head>
    <body>
        <p id="btn" style="width: 30px; height: 30px; background-color:black"></p>
        <script type="text/javascript" src="eventDOM.js"></script>
    </body></html>

Click and

Hello World

will appear, no problem. But the script model also has shortcomings. Based on the above html code, add a little js, as follows: <pre class="brush:php;toolbar:false">// js code// eventDOM.jslet btn = document.getElementById('btn')let btnClick = function() {     console.log('Hello World')}let btnClick2 = function() {     console.log('Hello World again')}btn.onclick = btnClick btn.onclick = btnClick2</pre>We found that now clicking only

Hello World again

will appear. Therefore, the script model only allows one node to add events of the same type once, and subsequent ones will overwrite the previous ones. Finally let us look at an interesting example:

<!-- html code --><html>
    <head>
        <title>eventDOM demo</title>
    </head>
    <body>
        <p id="btn3" style="width: 400px; height: 400px; background-color:pink">
            btn3            <p id="btn2" style="width: 300px; height: 300px; background-color:skyblue">
                btn2                <p id="btn1" style="width: 200px; height: 200px; background-color:lightgreen">
                    btn1                </p>
            </p>
        </p>
        <script type="text/javascript" src="eventDOM.js"></script>
    </body></html>
// js code// eventDOM.jslet btn1 = document.getElementById('btn1')let btn2 = document.getElementById('btn2')let btn3 = document.getElementById('btn3')btn1.onclick = function() {
    console.log('1')}btn2.onclick = function() {
    console.log('2')}btn3.onclick = function() {
    console.log('3')}

When we click btn3, the output is as follows:

It is in line with expectations, but what if we click btn1? The output is as follows:

This is a bit strange, Obviously we only added one listener for btn1, why does it feel like we added it together with btn2 and btn3? ​​The reason is because, although DOM0 has two models: event bubbling proposed by IE and event capturing proposed by Netscape, in fact DOM0 only supports event bubbling. Therefore, the event flow of clicking btn1 is as follows:

That is, the event flow also passes through btn2 and btn3, so their event processing is triggered. But obviously, this is not the result we want.

DOM2 events

After further specification, there is a DOM2-level event handler. Two methods are defined:

  • addEventListener() Add event listener
  • removeEventListener() Remove event listener

These two functions There are three parameters in the following table:

##eventStringThe name of the event to be monitored, such as 'click'. Note that there is no need to "on" herecallbackfunctionThe callback function to be executed to trigger the eventuseCaptureBoolean(default:false)Whether the event is processed in the capture phase

DOM2 中就可以對同一個節點綁定兩個以上的同類型事件監聽器了,看看下面例子:

<!-- html code --><html>
    <head>
        <title>eventDOM demo</title>
    </head>
    <body>
        <p id="btn" style="width: 200px; height: 200px; background-color:lightgreen"></p>
        <script type="text/javascript" src="eventDOM.js"></script>
    </body></html>
// js code// eventDOM.jslet btn = document.getElementById('btn')function hello() {
    console.log("Hello World")}function helloAgain() {
    console.log("Hello World again")}btn.addEventListener('click', hello, false)btn.addEventListener('click', helloAgain, false)

輸出如下:

解決了 DOM0 只能綁定一個同類型事件監聽器的缺點啦!值得注意的是,如果綁定同樣的監聽器兩次以上,仍然只會觸發一次。

再回到上面三個 p 的那個例子進行改寫如下:

<!-- html code --><html>
    <head>
        <title>eventDOM demo</title>
    </head>
    <body>
        <p id="btn3" style="width: 400px; height: 400px; background-color:pink">
            btn3            <p id="btn2" style="width: 300px; height: 300px; background-color:skyblue">
                btn2                <p id="btn1" style="width: 200px; height: 200px; background-color:lightgreen">
                    btn1                </p>
            </p>
        </p>
        <script type="text/javascript" src="eventDOM.js"></script>
    </body></html>
// js code// eventDOM.jslet btn1 = document.getElementById('btn1')let btn2 = document.getElementById('btn2')let btn3 = document.getElementById('btn3')btn1.addEventListener('click', function() {
    console.log('1')}, true)btn2.addEventListener('click', function() {
    console.log('2')}, true)btn3.addEventListener('click', function() {
    console.log('3')}, true)

注意,這邊我們把 addEventListener 的第三個參數設為 true,也就是事件會在捕獲階段觸發。點擊 btn1 輸出如下:

看到順序與 DOM0 的順序反過來了。首先最外層(btn3)的節點先被觸發了,而因為第三個參數被設為 true,事件會在捕獲階段就被處理,所以輸出才會是 3,2,1。如果都是 false,就會是 1,2,3。

可見 DOM2 的事件處理機制有了更彈性的操作空間。我們也可以在不同階段綁定事件監聽器,看看下面例子:

<!-- 沿用上一段 html 代碼 -->
// js code// eventDOM.jsbtn1.addEventListener('click',function() {
    console.log('btn1 capture')}, true)btn1.addEventListener('click',function() {
    console.log('btn1 bubble')}, false)btn2.addEventListener('click',function() {
    console.log('btn2 capture')}, true)btn2.addEventListener('click',function() {
    console.log('btn2 bubble')}, false)btn3.addEventListener('click',function() {
    console.log('btn3 capture')}, true)btn3.addEventListener('click',function() {
    console.log('btn3 bubble')}, false)

點擊 btn1 輸出如下:

改變一下順序,如下:

<!-- 沿用上一段 html 代碼 -->
// js code// eventDOM.jsbtn1.addEventListener('click',function() {
    console.log('btn1 bubble')}, false)btn1.addEventListener('click',function() {
    console.log('btn1 capture')}, true)btn2.addEventListener('click',function() {
    console.log('btn2 bubble')}, false)btn2.addEventListener('click',function() {
    console.log('btn2 capture')}, true)btn3.addEventListener('click',function() {
    console.log('btn3 bubble')}, false)btn3.addEventListener('click',function() {
    console.log('btn3 capture')}, true)

點擊 btn1 輸出如下:

注意 btn1 的輸出。雖然捕獲階段先發生了,但是因為 btn1 本身就是目標節點,所以在這種情況下,總結出規律:在目標元素上不區分冒泡還是捕獲,是根據腳本中的順序來執行。

有時候,我們希望對於某節點,不要再經過冒泡階段了,DOM2 也提供了相應函數,stopPropagation

<!-- 沿用上一段 html 代碼 -->
// js code// eventDOM.jsbtn1.addEventListener('click',function() {
    console.log('btn1 capture')}, true)btn1.addEventListener('click',function() {
    console.log('btn1 bubble')}, false)btn2.addEventListener('click',function(e) {
    e.stopPropagation()
    console.log('btn2 capture')}, true)btn2.addEventListener('click',function() {
    console.log('btn2 bubble')}, false)btn3.addEventListener('click',function() {
    console.log('btn3 capture')}, true)btn3.addEventListener('click',function() {
    console.log('btn3 bubble')}, false)

點擊 btn1 輸出如下:

可以看到,因為我們在 btn2 的捕獲階段就阻止了 btn2 的冒泡階段,所以 btn2 在捕獲後就不再繼續執行下去,確保不會冒泡,事件流如下:

加強一下前面提到的知識點,如果是在 btn1 阻止冒泡,會變成怎樣呢?

<!-- 沿用上一段 html 代碼 -->
// js code// eventDOM.jsbtn1.addEventListener('click',function(e) {
    e.stopPropagation()
    console.log('btn1 capture')}, true)btn1.addEventListener('click',function() {
    console.log('btn1 bubble')}, false)btn2.addEventListener('click',function() {
    console.log('btn2 capture')}, true)btn2.addEventListener('click',function() {
    console.log('btn2 bubble')}, false)btn3.addEventListener('click',function() {
    console.log('btn3 capture')}, true)btn3.addEventListener('click',function() {
    console.log('btn3 bubble')}, false)

點擊 btn1 輸出如下:

雖然我們對 btn1 阻止了冒泡,但是為什麼還是輸出了 btn bubble呢?原因就是前面提到了,目標節點不區分 捕獲/冒泡 階段,但是後面也就不會繼續冒泡了,算是個比較特殊的情況,可以稍微留意下。

結語

本篇大致介紹了 js 的事件流的各種模型以及階段上的工作任務,個人認為應該還算詳細。雖然個人感覺好像對編程本身沒有太明顯的幫助,但是還是算是 js 的一個重要的知識點,學習下也沒甚麼不好。若內容有誤,還歡迎指點!

相关免费学习推荐:javascript(视频)

Parameter Type Description

The above is the detailed content of An introduction to JavaScript’s event flow. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:csdn.net. If there is any infringement, please contact admin@php.cn delete