带你理解JS中的Events事件

Events

What’s events

Events are actions or occurrences that happen in the system you are programming, which the system tells you about so you can respond to them in some way if desired.

事件就是发生在系统中的动作,系统通知你你可以添加代码来响应它。(我想对于user interactive类型的事件应该是用户做出动作后,操作系统capture,然后放在 message queue中,然后chrome从queue中取出,然后一顿代码操作实现与你添加的代码绑定。)

the system produces (or “fires”) a signal of some kind when an event occurs, and provides a mechanism by which an action can be automatically taken (that is, some code running) when the event occurs.

这个绑定的代码自动执行的机制是chrome提供给你的。

In the case of the Web, events are fired inside the browser window, and tend to be attached to a specific item that resides in it — this might be a single element, set of elements, the HTML document loaded in the current tab, or the entire browser window. There are many different types of events that can occur. For example:

  • The user selects a certain element or hovers the cursor over a certain element.
  • The user chooses a key on the keyboard.
  • The user resizes or closes the browser window.
  • A web page finishes loading.
  • A form is submitted.
  • A video is played, paused, or finishes.
  • An error occurs.

Each available event has an event handler, which is a block of code (usually a JavaScript function that you as a programmer create) that runs when the event fires. When such a block of code is defined to run in response to an event, we say we are registering an event handler. Note: Event handlers are sometimes called event listeners — they are pretty much interchangeable for our purposes, although strictly speaking, they work together. The listener listens out for the event happening, and the handler is the code that is run in response to it happening.

每个可用的事件都有一个事件处理器,他通常是程序猿创建的一段JS代码,当事件触发时,这段代码会自动被执行。in terms as registering an event handler.

Ways of uising web events

There are a number of ways to add event listener code to web pages so it runs when the associated event fires.
有几种register event handler的方式:

  1. Event handler properties.
    即在DOM中元素的属性中添加,其中全局属性
    中就有event handler properties。
    Above the image is a list of interfaces which are based on the main Event interface.There are many types of events, some of which use other interfaces based on the main Event interface. Event itself contains the properties and methods which are common to all events.
    可以看出大概Event是base class, 其他都是继承而来的derived class。例如对于鼠标点击事件click属于MoseEvent,他是继承自Event,并且有自己的properties and methods。
    Syntax format such as :
const btn = document.querySelector('button');

btn.onclick = function() {
  const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')';
  document.body.style.backgroundColor = rndCol;
}
  1. inline event handlers — don’t use these
// maybe confused. Mix up your htlm and js.
<button onclick="bgChange()">Press me</button>

3.Adding and removing event handers
strongly recommand
The modern mechanism for adding event handlers is the addEventListener() (this is a method of EventTarget object) method, and removeEventListener to remove listener.
这种方式有很多好处:@1 可以方便remove event handler。For simple, small programs, cleaning up old, unused event handlers isn’t necessary — but for larger, more complex programs, it can improve efficiency。@2 可以在capture和bubbling phase 设置响应事件。 @3 方便在代码中为一个元素设置多个不通的handler。Plus, the ability to remove event handlers allows you to have the same button performing different actions in different circumstances — all you have to do is add or remove handlers.
such as:

/* When you are using this format the latter handler will overrall the formor one. 
myElement.onclick = functionA;
myElement.onclick = functionB;

*/ 
myElement.addEventListener('click', functionA);
myElement.addEventListener('click', functionB);
// Now myElement has two handler both can be run if click event fires.

Turn to overview the syntax format usage.

Other event concepts

In this section, we briefly cover some advanced concepts that are relevant to events.

Event objects

Sometimes inside an event handler function, you’ll see a parameter specified with a name such as event, evt, or e. This is called the event object, and it is automatically passed to event handlers to provide extra features and information.

Some important properties of Event parameter in event handler function
  1. e.target
    The target property of the event object is always a reference to the element the event occurred upon.
    e.target is incredibly useful when you want to set the same event handler on multiple elements and do something to all of them when an event occurs on them.
    Syntax format such as below:
const divs = document.querySelectorAll('div');

// e.target represents the divs[i] in  each iterate. It is a reference of divs[i].
for (let i = 0; i < divs.length; i++) {
  divs[i].onclick = function(e) {
    e.target.style.backgroundColor = bgChange();
  }
}

Preventing default behavior

Sometimes, you’ll come across a situation where you want to prevent an event from doing what it does by default. 有时,你会碰到你想要阻止一个事件的默认行为的情况。例如一个, 他的keyboard的默认行为就是在输入框中显示你输入的东西。在Qt中的lineEdit也是这样。你可以用这个方法阻止一些事件的默认行为,实现你个人定制化行为。 that is called customerised style behavior 。

Below is a snippet to show this (Bind js code to html in convenience in this):

    <html>
    <head>     
    </head>
<body>
    <div class = "container">
        <p>Please enter your name using lowercase letters only.</p>
        <form>
            <input type = "text" id = "my-textbox">
        </form>
    </div>
    <script >/* stopping keystrokes from reaching an edit field
* The following examle demonstrates how invilad text input can be stopped from reaching the input field
* with `preventDefault()`. Nowadays , you should usually use `native HTML form validation` instead. 
* 
*/

// The displayWaring() function presents a notification of a probelem.
function displayWarning(msg) {
    var warningBox = document.querySelector(".container");
    warningBox.innerHTML = msg;
}

function checkName(event) 
{
    // Obsolete properties 
    // charCode property returns a `Number` representing a system and 
    let charCode = event.charCode;
    if(charCode != 0) {
        if(charCode < 97 || charCode > 122) {
            event.preventDefault();
            displayWarning(`Please use lowercase letters only.
            charCode : ${charCode}
            `);
        }
    }
}

let myTextbox = document.getElementById("my-textbox");

// checkName disable you to enter Uppercase alphabets
myTextbox.addEventListener("keypress", checkName, false);	// bubbling by defaults.
</script>
    </body>
    </html>
<html>

Event bubbling and capture

This is the most important what I think.

The final subject to cover here is something that you won’t come across often, but it can be a real pain if you don’t understand it. Event bubbling and capture are two mechanisms that describe what happens when two handlers of the same event type are activated on one element.

Event bubbling and capture 是两种描述了当两个属于同种类型的事件处理器发生在一个元素上时发生何种事情的机制。就是当bubbling 和capture同时发生在一个元素上会先响应哪个?是bubbling?还是capture?还是我们可以设置响应哪个?
别着急,没看懂,继续往下看:

Bubbling and capturing explained
When an event is fired on an element that has parent elements (in this case, the <img>has the <div> as a parent), modern browsers run three different phases — the capturing phase, the target phase, and the bubbling phase.

  1. In the capturing phase:
    The browser checks to see if the element’s outer-most ancestor (<html>) has an onclickevent handler registered on it for the capturing phase, and runs it if so.
    Then it moves on to the next element inside <html>and does the same thing, then the next one, and so on until it reaches the direct parent of the element that was actually selected.
  2. In the target phase:
    The browser checks to see if the target property has an event handler for the click event registered on it, and runs it if so.
    Then, if bubbles is true, it propagates the event to the direct parent of the selected element, then the next one, and so on until it reaches the <html> element. Otherwise, if bubbles is false, it doesn’t propagate the event to any ancestors of the target.
  3. In the bubbling phase, the exact opposite of the capturing phase occurs:
    The browser checks to see if the direct parent of the element selected has an onclickevent handler registered on it for the bubbling phase, and runs it if so.
    Then it moves on to the next immediate ancestor element and does the same thing, then the next one, and so on until it reaches the <html> element.

上述官方文档中要点我都用背景色加粗表述出来了。
Note:我们可以为一个元素同时设置capturing和bubbling阶段两个阶段的event handler。
大致意思就是当一个event 触发在一个有父元素的元素上时,现代浏览器会依次运行三个不同的阶段的处理过程。capturing phase 从html到event.target的父元素; target phase 执行event.target, 如果bubbles 是true, 继续从内向外传播,如果为false,不会继续传播,到此为止; bubbling phase 从event.target的direct parent开始向外直到html元素。

Note
All JavaScript events go through the capturing and target phases. Whether an event enters the bubbling phase can be checked by the read-only bubbles property.

上述非常重要:所有javaScripts事件都会经历capturing and target阶段。是够一个事件进入到bubbling phase 取决于bubbles属性。



Note
Event listeners registered for the element aren’t at the top of hierarchy. For example, event listeners registered for the window and document objects are higher in the hierarchy.

实测,会一直执行到window如果绑定的话, 不仅仅是html元素。
below is a snippet to show bubbling and capture:

<html>
<head>
    <meta charset="utf-8">
    <title>Show video box example</title>
    <style>
        img {
            display: block;
            margin: 0px auto;
            width: 300px;
            height: 300px;
        }
    </style>
</head>

<body>
    <button>Display video</button>
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Sit, debitis alias non accusantium eaque doloremque a
        natus at, fugit officiis vitae est reprehenderit odit. Dolores porro error vero laborum assumenda?</p>
    <div class="hidden" style="width:100%; height:100%">
        <img src="images/1.jpg" alt="test bubbling">
    </div>

    <script>

        const btn = document.querySelector('button');
        const videoBox = document.querySelector('div');
        const video = document.querySelector('img');


        videoBox.addEventListener("click", function (e) {
            //e.stopPropagation();
            console.log(`videoBox: e.bubbles: ${e.bubbles}, 
            e.target: ${e.target},
            e.currentTarget:${e.currentTarget},
            e.eventPhase: ${e.eventPhase}.
            `);
        }, true); // capture phase
        videoBox.addEventListener("click", function (e) {
            e.stopPropagation();
            //e.stopImmediatePropagation();
            console.log(`videoBox: e.bubbles: ${e.bubbles}, 
            e.target: ${e.target},
            e.currentTarget:${e.currentTarget},
            e.eventPhase: ${e.eventPhase}.}
            `);
        }, false);    // bubbling phase
        //测试不让外层videoBox冒泡bubbling


        video.addEventListener("click", function (e) {
            console.log(`video: e.bubbles: ${e.bubbles}, 
            e.target: ${e.target},
            e.currentTarget:${e.currentTarget},
            e.eventPhase: ${e.eventPhase}.}
            `);
        }, true);    // bubbling phase

        video.addEventListener("click", function (e) {
            console.log(`video: e.bubbles: ${e.bubbles}, 
            e.target: ${e.target},
            e.currentTarget:${e.currentTarget},
            e.eventPhase: ${e.eventPhase}.}
            `);
        }, false);    // bubbling phase
        

        document.addEventListener("click", function (e) {
            console.log(`document: e.bubbles: ${e.bubbles}, 
            e.target: ${e.target},
            e.currentTarget:${e.currentTarget},
            e.eventPhase: ${e.eventPhase}.}
            `);
        }, false);
        document.addEventListener("click", function (e) {
            console.log(`document: e.bubbles: ${e.bubbles}, 
            e.target: ${e.target},
            e.currentTarget:${e.currentTarget},
            e.eventPhase: ${e.eventPhase}.}
            `);
        }, true);

        window.addEventListener("click", function (e) {
            console.log(`window: e.bubbles: ${e.bubbles}, 
            e.target: ${e.target},
            e.currentTarget:${e.currentTarget},
            e.eventPhase: ${e.eventPhase}.}
            `);
        }, false);
        window.addEventListener("click", function (e) {
            console.log(`window: e.bubbles: ${e.bubbles}, 
            e.target: ${e.target},
            e.currentTarget:${e.currentTarget},
            e.eventPhase: ${e.eventPhase}.}
            `);
        }, true);

        btn.onclick = function (e) {
            console.log(`btn: e.bubbles: ${e.bubbles}, e.target: ${e.target}, e.currentTarget:${e.currentTarget}
            `);
        };

    </script>
</body>
</html>

在这里插入图片描述

万茜茜是真的太好看了


其中有几个Event的属性:

  1. The currentTarget read-only property of the Event interface identifies the current target for the event, as the event traverses the DOM. It always refers to the element to which the event handler has been attached, as opposed to Event.target, which identifies the element on which the event occurred and which may be its descendant. 就是event handler在沿着DOM tree 进行bubbling或者capturing过程中,经过的每个当前Element。 而Target是event发生时那个Element。

  2. The eventPhase read-only property of the Event interface indicates which phase of the event flow is currently being evaluated. 就是现在event handler进行到上述说的3个 bubbling还是target还是capture阶段了。
    在这里插入图片描述

分析上述代码:分别为内层元素<img>和它的父元素<div>documentwindow分别添加了冒泡阶段和捕获阶段的eventhandler,使用addEventHandler() 第三个boolean参数为false(by defaults)添加了冒泡阶段的event handler;参数为true,添加了capture阶段的event handler。
然后在元素videoBox上用event object 的e.stopPropagation()阻止了事件进一步向上冒泡。

并且从代码运行截图可以看出browser of chrome 先执行capture阶段,然后在执行target阶段console中红色标出为capture阶段执行的代码,同时可以看出e.eventPhase属性为1.验证了官方文档中的第一个capture阶段。
蓝色的为target阶段,因为同时为内部img元素添加了capture和bubbling两个handler,所以会执行两次handler,同时可以看出e.eventPhase属性为2。
绿色为bubbling阶段,同时可以看出e.eventPhase属性为3,因为在videoBox的bubbling阶段的handler中执行了e.stopPropagate(), 所以它执行完后不会继续冒泡了。如果不执行这句代码,会一直冒泡到window元素上。

最后放几个链接:如果觉得好的话点个👍吧。花了3个小时写的。

Introduction to events
介绍DOM的官方文档和根据HTML生成DOM的live transfer
What’s Events
event.bubbles

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值