Как правилно да използвате prevenDefault (), stopPropagation () или да върнете невярно; за събития

Сигурен съм, че това е писано много пъти преди и вероятно има стотици отговори на StackOverflow. Въпреки това ние все още намираме кодови бази и многократно намираме злоупотребата (или взаимозаменяема употреба или комбинирана употреба) на event.preventDefault (), event.stopPropagation () и връщаме false ;.

Затова днес ще научим какви са разликите между трите и как точно функционират.

prevenDefault (), stopPropagation () и връщане false; не са взаимозаменяеми, нито са инструменти за проба и грешка.

Ще започнем с доста често срещан модел на потребителския интерфейс - панел за качване на файлове - и ще видим как всеки от тях влияе на неговото поведение.

С любезното съдействие на FineUploader

HTML

Нашият HTML се състои от три части:

  1. Вход за обработка на диалоговия прозорец за качване на файлове. Това е скрито (дисплей: няма;), тъй като ще задействаме диалоговия прозорец за качване, използвайки следните два елемента.
  2. Разделител с класа на file-upload__dropzone, който действа като основна „зона на пускане“, където ще можем да плъзгаме и пускаме файлове (кодът не е включен) или щракнете, за да отворим диалогов прозорец за качване на файлове.
  3. Етикет с класа на file-upload__btn - upload, който ще действа като бутона „Качване на файлове“, който при щракване ще отвори диалогов прозорец за качване на файл.

JavaScript

Нашият JavaScript, като нашия HTML, също се състои от три части:

  1. Функция за зареждане на файл за задействане на събитието за щракване върху въвеждането на файл.
  2. Присвояване както на divzone, така и на бутона на променливите.
  3. Добавяне на слушатели на събития към тези, които при щракване се позовават на функцията fileUpload.

Ако сега трябва да изпробваме това, може да видим някакво странно поведение - след като се отвори първият диалогов прозорец и сме избрали нашия файл, ще се отвори втори, който ще ни подкани отново. Продължете да четете и всичко ще бъде разкрито.

event.preventDefault ()

Предотвратява поведението на браузърите по подразбиране (като например отваряне на връзка), но не спира събитието да бълбука DOM.

В нашия сценарий щракването върху бутона „Качване на файлове“ ще извика функцията за зареждане на файла, както бихме очаквали.

Като маркер обаче има и поведение по подразбиране - това е да се ориентира в браузъра до местоположението в атрибута href. В този случай имаме този набор на #, което в повечето браузъри просто ще доведе до връщане на страницата към върха.

Скачането обратно в горната част на страницата всъщност не е нашето желано поведение, така че можем да предотвратим това, използвайки метода prevenDefault. Това предотвратява поведението на елемент по подразбиране.

Променяйки нашия JavaScript код, можем да поправим това, така че щракването върху връзката предотвратява поведението по подразбиране на навигацията до местоположението в атрибута href, но все пак отваря диалоговия прозорец за качване на файлове.

Тук взехме събитието за щракване и предотвратихме поведението му по подразбиране с помощта на event.preventDefault (), след което се позовахме на функцията fileUpload ().

Все още имаме диалогов прозорец, който ще се появи два пъти, но се надяваме, че следващият раздел ще реши този проблем.

event.stopPropagation ()

Предотвратява събитието да бълбука DOM, но не спира поведението на браузърите по подразбиране.

За задълбочено обяснение на мехурството на събитията, бих препоръчал тази статия за разпространението на събитията. Но по същество, когато дадено събитие се извика на елемент, това събитие мехури DOM и се извиква върху всички родители на елементи.

В нашия случай това означава, че когато кликнем върху бутона „Качване на файл“, това събитие ще бъде извикано и върху всички негови родителски елементи, включително нашата dropzone.

За да видим това в действие, можем да премахнем извикването fileUpload () в слушателя на събитията с бутони и функцията все още ще бъде извикана, когато щракнем върху бутона, защото събитието с щракване ще издува DOM и ще бъде повикано в dropzone.

Това балообразуване е пример за разпространение на събития, в който започва да играе методът stopPropagation. Можем да го използваме, за да предотвратим това поведение по подразбиране на балон, така че събитието да бъде регистрирано само от елемента, на който е извикан.

Сега виждаме, че не само събитието щракване не балон DOM, но чрез премахване на метода prevenDefault призовава тагът да действа отново, както трябва, чрез навигиране до неговия атрибут href.

Но това не е това, което искаме. Искахме да се обадим на функцията fileUpload и също да предотвратим поведението на елемента по подразбиране и да предотвратим появата на DOM в събитието.

Можем да използваме както prevenDefault, така и stopPropagation, след което да извикаме функцията fileUpload, така.

върнете невярно;

Обикновено се вижда в jQuery код, той предотвратява поведението на браузърите по подразбиране, предотвратява събитието от барботиране на DOM и незабавно се връща от всяко обратно извикване.

В vanilla JavaScript връщането на false не оказва влияние върху поведението по подразбиране или разпространението на събитията на елемента, както можем да видим тук, то действа точно както в началото.

Той извиква събитието за щракване върху бутона, също така се придвижва до стойността на href, след което издува DOM, като извиква събитието за щракване и върху падащата зона.

Въпреки това…

… В контекста на jQuery, връщането на фалшиво незабавно ще излезе от обратното извикване на слушателите на събитието. Това има ефект и на двете:

  1. Предотвратяване на поведението по подразбиране - навигиране в браузъра до атрибута href на маркера.
  2. Спиране на всяко разпространение на събитие - спиране на събитието за щракване от бълбукане на DOM.

Ако префабрикуваме кода си на jQuery, можем да видим това на практика.

Ние наричаме метода fileUpload, след което връщаме невярно, за да предотвратим поведение по подразбиране или разпространение на събития.

заключение

Трябва да използваме тези инструменти правилно и разумно.

Следващия път, когато сме в подобна ситуация, не трябва да играем само с event.preventDefault (), event.stopPropagation () и да връщаме false; докато не получим желания резултат.

Трябва да помислим какво искаме да постигнем и как да стигнем дотам - не чрез проба и грешка и късмет - а чрез мислене през проблема и прилагане на правилното решение.