In den beiden vorherigen Blogs haben wir den zugehörigen Inhalt der Ereignisverteilung in Android besprochen. In diesem Blog werden wir daher kurz den Ereignisverteilungsmechanismus in HTML oder Javascript diskutieren und einen einfachen Vergleich anstellen.
Im Frontend gibt es drei Möglichkeiten, Ereignisse zu binden.
(1). Im DOM binden.
<!-- @author www.yaoxiaowen.com --><div id="div-1" onclick="div1click()">div - 1</div><script>function div1click() {console.log("click div-1");}</script>
(2).
<div id="div-2"> div - 2</div><script>document.getElementById("div-2").onclick = function () {console.log("click div-2");}</script>
(3). Binden Sie, indem Sie sich das Ereignis anhören. addEventListener
<div id="div-3">div - 3</div><script>document.getElementById("div-3").addEventListener("click", div3Click);function div3Click() {console.log("click div-3");}</script>
Für die ersten beiden Ereignisbindungen Die Methode ist relativ einfach.
1. Die erste Möglichkeit zum Binden in Dom: Wenn mehrere Funktionen gleichzeitig registriert sind, wird die erste gebundene Funktion ausgeführt.
bedeutet, dass, wenn es in der folgenden Form vorliegt:
<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>
das Ausgabeergebnis des Klickens wie folgt lautet:
click div-1 click-1
2. Die zweite Bindung erfolgt in einem Skript. Wenn mehrere Funktionen gleichzeitig registriert werden, wird die letzte gebundene Funktion ausgeführt.
bedeutet, dass in der folgenden Form:
<!-- @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>
das Ausgabeergebnis lautet:
click div-2 第二次注册
3. Und die dritte addEventListener
Methode ist komplizierter und wird in diesem Artikel hauptsächlich besprochen.
Zunächst muss klargestellt werden, dass der größte Unterschied zwischen der dritten Methode und den ersten beiden Methoden darin besteht, dass, wenn die ersten beiden Methoden mehrere Funktionen registrieren, nur eine ausgeführt wird, während bei der dritten Methode nur eine ausgeführt wird Wenn mehrere Funktionen registriert sind, werden alle Funktionen ausgeführt.
Nehmen wir an, dass es drei ineinander verschachtelte Divs gibt. Die äußerste Ebene ist outer
, die in middle
verschachtelt ist, und middle
ist in einem kleinen inner
verschachtelt. Die Form von
ist wie folgt:
<div id="outer-div" class="common"><div id="middle-div" class="common"><div id="inner-div" class="common"></div></div></div>
Siehe Bild:
Wenn wir auf das Innerste inner
klicken , dann ist dieses Ereignis Was ist die auslösende Sequenz?
Ich denke, wir können es so verstehen, egal ob für Android oder das Frontend: Wenn ein Ereignis auftritt, muss es zuerst von der äußersten Ansicht erfasst und dann wiederum nach innen weitergeleitet werden.
Dieses Prinzip wird im ersten Absatz der Ereignisverteilung von Android View erwähnt, da das Auftreten dieses Ereignisses immer zuerst von der Hardware generiert werden muss und der Treiber->Kernel->Framework usw. der Reihe nach nach oben weitergegeben wird. Egal um welches Gerät es sich handelt (Mobiltelefon oder PC), daran ändert sich nichts.
Zurück zum Problem im Frontend, wir können es so verstehen: outer
nimmt es zuerst wahr, dann middle
nimmt es wahr und dann inner
nimmt es wahr. Das ist nicht anders als bei Android, aber die Frage ist, wie man dabei damit umgeht.
Lassen Sie uns einen Blick zurück auf die addEventListener
-Methode werfen.
Der Prototyp dieser Methode sieht so aus.
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;
Obwohl p zunächst auf func1 zeigte, zeigte es später auf func2. Von nun an hat p nichts mehr mit func1 zu tun.
Ich habe den Quellcode des Browsers nicht gesehen, daher verstehe ich nicht, warum addTouchListener
mehrere Abhörfunktionen ausführen kann, aber das unterscheidet sich tatsächlich von den gängigen Programmiergewohnheiten.
In Android: Sobald eine Ansicht ein Ereignis verbraucht (gibt true zurück). Dann konsumieren andere Ansichten keine Ereignisse mehr. Ihr onTouchEvent
wird nicht mehr aufgerufen. Aber in js können mehrere Elemente dieses Ereignis verarbeiten. Ich denke, das ist wie onTouchEvent
, obwohl es aufgerufen und entsprechender Code geschrieben wurde, um die Geschäftslogik zu handhaben, hat es false zurückgegeben.
Was ihren Übertragungsprozess betrifft, denke ich, dass sie fast gleich sind, beide ähneln der Übertragungsreihenfolge von U
Glyphen. Obwohl das onTouchEvent
der zugrunde liegenden Ansicht in Android „true“ zurückgibt, wird das onTouchEvent
anderer Ansichten nicht mehr aufgerufen. Die dispatchTouchEvent
-Methode jeder Ansicht muss jedoch noch aufgerufen werden.
Obwohl die Lieferreihenfolge von Android und js dieselbe ist, sind die Zwischenabfang- und Verarbeitungsprozesse unterschiedlich.
Aus dieser Perspektive scheint die Ereignisverteilung und -bereitstellung in Android und JS zwar sehr unterschiedlich zu sein, ich denke aber, dass sie im Wesentlichen etwas ähnlich sind. Sie werden alle von außen nach innen weitergegeben, vom übergeordneten Element zum untergeordneten Element.
Während ich diese Inhalte studierte, beschrieb ich auch den Ereignisverteilungsprozess in Android mit meinen iOS-Kollegen im Unternehmen und fragte sie, was der Mechanismus in iOS sei. Sie sagten, dass dies tatsächlich der Fall sei Bereiche, in denen der Programmierbereich auf unterschiedlichen Wegen das gleiche Ziel erreicht.
Ein kleiner Haftungsausschluss: Da ich ein Anfänger in js bin, habe ich den Quellcode des Browsers noch nie gesehen und verstehe den zugrunde liegenden Implementierungsmechanismus nicht, also habe ich Ich habe keine Ahnung vom Ereignisbereitstellungsmechanismus im Front-End. Die Beschreibung befindet sich möglicherweise auf der oberflächlichen Präsentationsebene, aber was ist das Wesentliche oder wie wird es im Quellcode durchgeführt? Ich weiß nicht.
Das ist genau wie bei Chemiestudenten am College: Die in der High School gelernten chemischen Formeln sind oberflächlich. Sogar falsch. Aufgrund des Verständnisniveaus und der Grundkenntnisse der Oberstufenschüler können die Oberstufenlehrbücher jedoch nur so oberflächlich sein. Dem Wissen in den Oberstufenlehrbüchern zufolge können chemische Phänomene jedoch bereits zu einem gewissen Grad erklärt werden. Dieser Blog ist im Wesentlichen ähnlich. Vielleicht ist mein Verständnis oberflächlich oder sogar falsch, aber nach diesem Verständnis ist es tatsächlich richtig, die Ausführungsreihenfolge jeder Abhörfunktion zu analysieren.
Wenn es ein Missverständnis gibt, geben Sie mir bitte Feedback.
Das obige ist der detaillierte Inhalt vonVergleichende Analyse von Ereignisverteilungsmechanismen in Android und JavaScript. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!