In the previous two blogs, we discussed the relevant content of event distribution in Android. In this blog, we will briefly discuss the event distribution mechanism in HTML or javascript and make a simple comparison.
In the front-end, there are three ways to bind events.
(1). Bind in DOM.
<!-- @author www.yaoxiaowen.com --><div id="div-1" onclick="div1click()">div - 1</div><script>function div1click() {console.log("click div-1");}</script>
(2). Bind in the script.
<div id="div-2"> div - 2</div><script>document.getElementById("div-2").onclick = function () {console.log("click div-2");}</script>
(3). By listening to the event addEventListener
Binding
<div id="div-3">div - 3</div><script>document.getElementById("div-3").addEventListener("click", div3Click);function div3Click() {console.log("click div-3");}</script>
For the first two event bindings The method is relatively simple.
1. The first way to bind in dom, if multiple functions are registered at the same time, the first bound function will be executed.
means that when the form is as follows:
<div id="div-1" onclick="div1click_1()",onclick="div1click_2()">div - 1</div><script>function div1click_1() {console.log("click div-1 click-1");}function div1click_2() {console.log("click div-1 click-2");}</script>
, the output result of clicking is as follows:
click div-1 click-1
2. The second type is in the script Binding is performed, and if multiple functions are registered at the same time, the last bound function is executed.
means that when the form is as follows:
<!-- @author www.yaoxiaowen.com --><div id="div-2"> div - 2</div><script>document.getElementById("div-2").onclick = function () {console.log("click div-2 第一次注册");}document.getElementById("div-2").onclick = function () {console.log("click div-2 第二次注册");}</script>
, the output result is:
click div-2 第二次注册
3. For the third type The addEventListener
method is more complicated, which is what we mainly discuss in this article.
First of all, it is necessary to clarify that the biggest difference between the third method and the first two methods is that if multiple functions are registered in the first two methods, only one will be executed, while in the third method, if multiple functions are registered, each function will be executed. The functions will all be executed.
We assume that there are three divs nested in each other. The outermost layer is outer
, which is nested in middle
, and middle
is nested again. Holding a small inner
.
The form is as follows:
<div id="outer-div" class="common"><div id="middle-div" class="common"><div id="inner-div" class="common"></div></div></div>
See the picture:
When we click on the innermost inner
, then this What is the triggering sequence of events?
I think we can understand it this way, whether it is for Android or the front end, when an event occurs, it must be sensed by the outermost view first, and then passed inward in turn.
This principle is mentioned in the first paragraph of Android View's event distribution, because the occurrence of this event always must be generated from the hardware first, and the driver->kernel->framework and so on are passed upward in sequence. No matter which device it is, (mobile phone or PC) this will not change.
Back to the problem in the front end, we can understand it this way, outer
is perceived first, then middle
is perceived, and then inner
Only then did I feel it. This is no different from that in Android, but the question is how to deal with it in the process.
Let’s look back at the addEventListener
method.
The prototype of this method is like this.
document.addEventListener(event, function, useCapture)
关于它的参数。event
是描述事件名称的字符串,比如click
,(注意不是onclick
)。function
是事件触发后要执行的函数。那么第三个参数useCapture
是干啥的呢。
这就说到了前端中事件执行的两种不同的策略,冒泡
与 捕获
。
冒泡
:从内向外,就像你在湖心扔了一粒石头,形成的波纹都是 从内向外扩散的,意思就是,三个view都注册监听了同种类型的事件,那么inner
先执行,其次才是middle
-> outer
。
捕获
:从外向内,就像人类狩猎围成的包围圈一样,越来越小。换成我们demo的场景,事件是outer
先执行,然后其次是 middle
-> innder
。
所以第三个参数useCapture
,其实是个boolean
类型的:
true:捕获阶段执行。
false:冒泡阶段执行。(默认值)。
那么为什么会存在这两种截然相反的事件执行策略呢,这就要从当年微软与网景的浏览器大战说起了。这两种方式是这两家公司分别选择的策略。后来w3c为了统一,就两种方式都保留了。
那么如果对于outer,middle,inner每个元素都注册了多个监听事件,有的冒泡,有的排序,那么这个执行顺序又是什么呢。
本篇文章中,我们说“注册了多个监听事件”,默认是说同种类型的,比如都是"click"。不同类型的,比如一个“mousedown”,一个“click”,这当然没啥关系。
假设我们触发事件的焦点是在 inner 元素中。
手动画张图方便理解这个问题。
见图片:
事件整体的传递顺序是 1 -> 2 -> 3 -> 4.
outer
首先感知到事件。然后传递到middle。(图片当中的 1 过程),该过程中,事件捕获前进。如果碰到某个元素注册了捕获函数,则执行函数,如果某个元素(比如middle)注册了多个捕获函数又会怎么样呢?答案是按照它们注册的顺序都执行。事件传递到 inner,(图片当中的 2 过程),如果inner同时也注册了多个捕获函数和冒泡函数,则很简单的,按照它们的注册顺序执行。(此时不分什么冒泡还是捕获类型的)。
然后事情再倒过来传递,(图片中的3 -> 4),再传递到middle和outer,在这个过程中,如果碰到某个元素注册了冒泡函数,则执行函数,如果某个元素(比如middle)注册了多个冒泡函数,则按照它们的注册顺序都执行。
这个执行的顺序解释完了,来看一个demo。
function run() {outerDiv = document.getElementById("outer-div");middleDiv = document.getElementById("middle-div");innerDiv = document.getElementById("inner-div");outerDiv.addEventListener("click", outerClick_1);outerDiv.addEventListener("click", outerClick_2, true);outerDiv.addEventListener("click", outerClick_3, true);middleDiv.addEventListener("click", middleClick_1);middleDiv.addEventListener("click", middleClick_2, true);innerDiv.addEventListener("click", innerClick_1);innerDiv.addEventListener("click", innerClick_2, true);innerDiv.addEventListener("click", innerClick_3);}<!-- @author www.yaoxiaowen.com -->function outerClick_1() { console.log("outer 1");}function outerClick_2() {console.log("outer 2");}function outerClick_3() {console.log("outer 3");}function middleClick_1() {console.log("middle 1");}function middleClick_2() {console.log("middle 2");}function innerClick_1() {console.log("inner 1");}function innerClick_2() {console.log("inner 2");}function innerClick_3() {console.log("inner 3");}
猜想一下,此时点击 inner
,则打印的顺序会是什么呢。
答案我就不贴出来了,感兴趣的可以参考 。
分别学习了android和js中的事件分发,其实感觉起来有相同的地方,也有不同的地方。
最大的不同是在于,addEventListener
方法竟然可以注册多个监听函数同时起作用,这点很让我震惊。因为在我的潜意思里,就像下面这段代码:
void func1(int a){//do something}void func2(int a){//do something}int (*p)(int) = func1;//do somethingp = func2;
Although p initially pointed to func1, it later pointed to func2. Then from now on, p has nothing to do with func1.
I haven’t seen the browser source code, so I don’t understand why addTouchListener
can execute multiple listening functions, but this is indeed different from mainstream programming habits.
In Android, once a view consumes an event (return true). Then other views will no longer consume events. Their onTouchEvent
will no longer be called. But in js, multiple elements can handle this event. I think this is like onTouchEvent
, although it was called and corresponding code was written to handle the business logic, but it returned false.
As for their delivery process, I think they are almost the same. They are all delivered in a sequence similar to the U
glyph. Although the onTouchEvent
of the underlying view in Android returns true, there will no longer be the onTouchEvent
of other views to call. But the dispatchTouchEvent
method of each view still needs to be called.
So although the delivery order of android and js is the same, the intermediate interception and processing processes are different.
From this perspective, although the event distribution and delivery in android and js seem to be very different, I think they are somewhat similar in essence. They are all passed from outside to inside, from parent elements to child elements.
While studying these contents, I also described the event distribution process in Android with my iOS colleagues in the company, and asked them what the mechanism is in iOS. They said that it is actually similar. Maybe these are the places where the same goal is reached by different paths in the programming field. .
Disclaimer: Because I am a beginner in js, I have never seen the source code of the browser, and I do not understand the underlying implementation mechanism, so I have no idea about the event delivery mechanism in the front end. The description may be at the superficial presentation level, but what it is in essence, or how to do it in the source code. I don’t know.
This is just like for college chemistry students, the chemical formulas learned in high school are superficial. Even wrong. It's just that due to the understanding level and basic knowledge of high school students, the high school textbooks can only be so superficial. However, according to the knowledge in the high school textbooks, chemical phenomena can be explained to a certain extent. This blog is similar. Perhaps in essence, my understanding is superficial or even wrong, but according to this understanding, it is indeed correct to analyze the execution order of each listening function.
If there is any misunderstanding, please give me feedback.
The above is the detailed content of Comparative analysis of event distribution mechanisms in Android and JavaScript. For more information, please follow other related articles on the PHP Chinese website!