Maison  >  Article  >  interface Web  >  Analyse comparative des mécanismes de distribution d'événements sous Android et JavaScript

Analyse comparative des mécanismes de distribution d'événements sous Android et JavaScript

零下一度
零下一度original
2017-06-26 13:35:281380parcourir

Dans les deux blogs précédents, nous avons discuté du contenu associé à la distribution d'événements dans Android, donc dans ce blog, nous discuterons brièvement du mécanisme de distribution d'événements en html ou javascript et ferons une comparaison simple.

Dans le front-end, il existe trois façons de lier des événements.

(1). Lier dans DOM.

<!-- @author www.yaoxiaowen.com --><div id="div-1" onclick="div1click()">div - 1</div><script>function div1click() {console.log("click div-1");}</script>

(2). Lier dans le script.

<div id="div-2"> div - 2</div><script>document.getElementById("div-2").onclick = function () {console.log("click div-2");}</script>

(3). Lier en écoutant l'événement addEventListener

  <div id="div-3">div - 3</div><script>document.getElementById("div-3").addEventListener("click", div3Click);function div3Click() {console.log("click div-3");}</script>

Pour les deux premières liaisons d'événement. la méthode est relativement simple.

1. La première façon de se lier dans dom, si plusieurs fonctions sont enregistrées en même temps, la première fonction liée sera exécutée.
signifie que lorsqu'il se présente sous la forme suivante :

<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>

le résultat de sortie du clic est le suivant :

    click div-1 click-1

2. La deuxième liaison est effectuée dans un script. Si plusieurs fonctions sont enregistrées en même temps, la dernière fonction liée sera exécutée.
signifie que lorsqu'il se présente sous la forme suivante :

<!-- @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>

le résultat de sortie est :

    click div-2 第二次注册

3. Et la troisième méthode addEventListener est plus compliquée, c'est ce dont nous discutons principalement dans cet article.

Tout d'abord, il est nécessaire de préciser que la plus grande différence entre la troisième méthode et les deux premières méthodes est que si les deux premières méthodes enregistrent plusieurs fonctions, une seule sera exécutée, alors que dans la troisième méthode , si plusieurs fonctions sont enregistrées, chacune des fonctions sera toutes exécutées.

Supposons qu'il y ait trois divs imbriqués les uns dans les autres. La couche la plus externe est outer, qui est imbriquée dans middle, et middle est imbriquée dans un petit inner. La forme de
est la suivante :

 <div id="outer-div" class="common"><div id="middle-div" class="common"><div id="inner-div" class="common"></div></div></div>

Voir l'image :
Analyse comparative des mécanismes de distribution d'événements sous Android et JavaScript

Quand on clique sur le inner le plus intérieur , alors cet événement est Quelle est la séquence de déclenchement ?

Je pense que nous pouvons le comprendre de cette façon, que ce soit pour Android ou le front-end, lorsqu'un événement se produit, il doit d'abord être détecté par la vue la plus externe, puis transmis à son tour vers l'intérieur.
Ce principe est mentionné dans le premier paragraphe de la distribution des événements d'Android View, car l'occurrence de cet événement doit toujours être générée à partir du matériel en premier, et le pilote->noyau->framework et ainsi de suite sont transmis vers le haut dans l'ordre. Quel que soit l’appareil (téléphone portable ou PC), cela ne changera pas.

Revenons au problème du front-end, nous pouvons le comprendre de cette façon, outer le perçoit d'abord, puis middle le perçoit, et ensuite inner le perçoit. Ce n’est pas différent de celui d’Android, mais la question est de savoir comment gérer cela dans le processus.

Retour sur la méthode addEventListener.
Le prototype de cette méthode est comme ça.

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 元素中。

手动画张图方便理解这个问题。

见图片:

Analyse comparative des mécanismes de distribution d'événements sous Android et JavaScript

事件整体的传递顺序是 1 -> 2 -> 3 -> 4.

  1. outer首先感知到事件。然后传递到middle。(图片当中的 1 过程),该过程中,事件捕获前进。如果碰到某个元素注册了捕获函数,则执行函数,如果某个元素(比如middle)注册了多个捕获函数又会怎么样呢?答案是按照它们注册的顺序都执行。

  2. 事件传递到 inner,(图片当中的 2 过程),如果inner同时也注册了多个捕获函数和冒泡函数,则很简单的,按照它们的注册顺序执行。(此时不分什么冒泡还是捕获类型的)。

  3. 然后事情再倒过来传递,(图片中的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;

Bien que p ait initialement pointé vers func1, il a ensuite pointé vers func2. À partir de maintenant, p n’a plus rien à voir avec func1.

Je n'ai pas vu le code source du navigateur, donc je ne comprends pas pourquoi addTouchListener peut exécuter plusieurs fonctions d'écoute, mais c'est en effet différent des habitudes de programmation traditionnelles.

  • Sous Android, une fois qu'une vue consomme un événement (retour vrai). Les autres vues ne consommeront alors plus d’événements. Leur onTouchEvent ne sera plus appelé. Mais en js, plusieurs éléments peuvent gérer cet événement. Je pense que c'est comme onTouchEvent, bien qu'il ait été appelé et que le code correspondant ait été écrit pour gérer la logique métier, il a renvoyé false.

  • Quant à leur processus de transmission, je pense qu'ils sont presque les mêmes, les deux sont similaires à l'ordre de transmission des U glyphes. Bien que le onTouchEvent de la vue sous-jacente dans Android renvoie vrai, il n'y aura plus d'appel au onTouchEvent des autres vues. Mais la méthode dispatchTouchEvent de chaque vue doit encore être appelée.

  • Ainsi, bien que l'ordre de livraison d'Android et de JS soit le même, les processus intermédiaires d'interception et de traitement sont différents.

De ce point de vue, bien que la distribution et la livraison des événements dans Android et js semblent être très différentes, je pense qu'elles sont quelque peu similaires dans leur essence. Ils sont tous transmis de l'extérieur vers l'intérieur, des éléments parents aux éléments enfants.

En étudiant ces contenus, j'ai également décrit le processus de distribution d'événements sous Android avec mes collègues iOS de l'entreprise, et leur ai demandé quel était le mécanisme dans iOS. Ils ont dit que c'était en fait similaire. domaines où différentes approches mènent au même objectif dans le domaine de la programmation.

  • Un petit avertissement : parce que je suis débutant en js, je n'ai jamais vu le code source du navigateur, et je ne comprends pas le mécanisme d'implémentation sous-jacent, donc je Je n'ai aucune idée du mécanisme de transmission des événements dans le front-end. La description est peut-être au niveau de la présentation superficielle, mais quelle est l'essence ou comment le faire dans le code source. Je ne sais pas.

  • C'est comme pour les étudiants en chimie au collège, les formules chimiques apprises au lycée sont superficielles. Même faux. C'est juste qu'en raison du niveau de compréhension et des connaissances de base des lycéens, les manuels du lycée ne peuvent être que superficiels. Cependant, sur la base des connaissances contenues dans les manuels du lycée, les phénomènes chimiques peuvent déjà être expliqués dans une certaine mesure. Ce blog est similaire. Peut-être qu'au fond, ma compréhension est superficielle ou même erronée, mais selon cette compréhension, il est effectivement correct d'analyser l'ordre d'exécution de chaque fonction d'écoute.

En cas de malentendu, veuillez me faire part de vos commentaires.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn