Javascript-форум (https://javascript.ru/forum/)
-   Events/DOM/Window (https://javascript.ru/forum/events/)
-   -   Назначение обработчиков и SPA (https://javascript.ru/forum/events/69898-naznachenie-obrabotchikov-i-spa.html)

GeekHacker 25.07.2017 22:56

Назначение обработчиков и SPA
 
Доброго времени.
Нужен совет от гуру.
Сразу скажу, что с web-разработкой знаком давно. Но что касается webА, то работал преимущественно с php. На js тоже успешно пишу, но не считаю его основным языком. Так что белых пятен хватает.
Задача следующая: требуется написать сайтик, но сайт должен представлять собой SPA. Никаких перезагрузок страниц, всё исключительно на ajaxЕ со всеми вытекающими и т.д.
Стоит отметить, что предполагается достаточно большое количество страниц. На каждой странице большое количество элементов взаимодействия с пользователем: ссылочки, кнопочки, формочки... Страницы, как правило, неоднотипные. Т.е. каждая страница, кроме пары блоков, не похожа на любую другую.
И тут меня начинают мучать сомнения. Как же наиболее эффективно организовать назначение обработчиков на события.
Рассматривается два варианта.
Первый.. Делегирование. На какой-то общий элемент (контейнер) навесить все обработчики.
Второй.. Навешивать обработчики через атрибуты элементов.
Всегда придерживался правила не смешивать html и js. С этой позиции делегирование представляется более правильным. Но не будет ли это слишком накладно в данном конкретном случае? Ведь когда внутри контейнера у нас произойдёт, скажем, клик, то у нас же запустятся все обработчики данного события на контейнере. А их будет много.
Вариант с атрибутами кажется менее накладным, но как-то и нравится меньше. Менее красиво что ли...
В общем, готов выслушать мнение сообщества.
Заранее благодарю.

laimas 26.07.2017 05:18

Цитата:

Сообщение от GeekHacker
Ведь когда внутри контейнера у нас произойдёт, скажем, клик, то у нас же запустятся все обработчики данного события на контейнере.

С чего вдруг? Два элемента А и В делегируют обработку щелчка родителю. Если щелкнули по В, то родителем будет обработан щелчок именно по нему, а не по А, так у него событие "автоматом" не возникнет. Кроме того можно использовать пространство имен.

GeekHacker 26.07.2017 10:19

ну почему же? Есть два элемента с id a и с id b внутри родителя с id d.
Мы хотим обрабатывать клики на a и b через делегирование. Для чего вешаем два обработчика на d.
При клике на любой из элементов будут запускаться оба обработчика.
Другое дело, что внутри обработчиков мы вычисляем event.target и полезный код будет выполнен только в случае, если event.target тот, что нам нужен, но это не отменяет того факта, что запустятся оба обработчика.
Топорный пример
var x = 2;
document.addEventListener('DOMContentLoaded', function(){
	//первый обработчик
	document.getElementById('d').addEventListener('click', function(event){
		x++;
		var target = event.target;
		while(target != this){
			if(target.id == 'a'){
				alert('Вы кликнули по элементу с ID "a"');
				return;
			}
			else
				target = target.parentNode;
		}
	});
	//второй обработчик
	document.getElementById('d').addEventListener('click', function(event){
		x++;
		var target = event.target;
		while(target != this){
			if(target.id == 'b'){
				alert('Вы кликнули по элементу с ID "b"');
				return;
			}
			else
				target = target.parentNode;
		}
	});
});

По клику на любом элементе мы увидим сообщение (одно), т.к. определив event.target мы всё правильно разрулили, но значением переменной x будет 2. Т.к. оба обработчика инкрементировали предыдущее её значение.
Да, можно было бы повесить один обработчик и в условиях зависимо от event.target всё разруливать, но это вообще не вариант. Т.к. логики будет много и там запутаться можно будет.

laimas 26.07.2017 10:32

Цитата:

Сообщение от GeekHacker
При клике на любой из элементов будут запускаться оба обработчика.

С чего вдруг, если событие одно, а делегирование, это определение источника события?

GeekHacker 26.07.2017 11:14

Ну хотябы потому, что в данном случае мы вешаем на один элемент два обработчика события click. Разве нет? Запустите код из примера и посмотрите сами.

laimas 26.07.2017 11:18

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 
<style>

</style> 
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script>
$(function() {
    $('div').on('click', 'a', function(e) {
        alert(e.target.tagName)
    });
    
    $('div').on('click', 'span', function(e) {
        alert(e.target.tagName)
    });
});
</script> 
</head>
<body>
<div>
<a>A</a>
<span>Span</span>
</div>
</body>
</html>


Проверяйте, у каждого элемента будет свой обработчик, хотя делегируют они его одному родителю. При делегировании будет определяться источник события, в этом вся соль.

GeekHacker 26.07.2017 13:17

А я разве утверждаю обратное?
Но если уж придираться к мелочам, то у дочерних элементов вообще нет обработчиков. Все обработчики мы вешаем на родителя. И срабатывают они на родителе. и при возникновении события сработает их столько, сколько мы их повесили на родителя.
А вся эта магия с делегированием работает исключительно благодаря тому, что события могут всплывать по структуре DOM. и что в объекте события нам доступен реальный источник события. Разница между target и currentTarget.
event.target - элемент на котором произошло событие и от которого оно начало всплытие.
event.currentTarget - элемент, на котором сработал обработчик события.
Я специально не стал использовать в примере какие-либо библиотеки типа JQuery, т.к. получается менее наглядно.
Берите мой пример и при помощи контрольной переменной смотрите сколько было срабатываний обработчиков при клике на любом из дочерних элементов.

laimas 26.07.2017 13:34

Цитата:

Сообщение от GeekHacker
И срабатывают они на родителе. и при возникновении события сработает их столько, сколько мы их повесили на родителя.

С чего вдруг при щелчке на одном элементе, возникнут щелчки на всех других дочерних?

В голове что-то не укладывается. Хрен с ним, пусть будет так:

$a = [
    'a' => function() {},
    'b' => function() {}    
]


Если $a['b'](), то означает ли, что при этом будет выполнено и $a['a']()? А почему при щелчке по Span должен выполняться и обработчик А?

О чем речь?

Rise 26.07.2017 13:43

GeekHacker,
А что вы предлагаете? Да, нет нативного метода для того что вы хотите. Вы можете использовать либо кастомный метод либо ждать когда появится нативный.

laimas 26.07.2017 13:48

GeekHacker,
доперло что не нравится - цена метода?


Часовой пояс GMT +3, время: 14:28.