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 должен выполняться и обработчик А?

О чем речь?

laimas 26.07.2017 13:48

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

GeekHacker 26.07.2017 14:25

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

GeekHacker 26.07.2017 14:33

Точнее не событие срабатывает на родителе, а событие всплывает до родителя, на котором срабатывают обработчики.
Да, именно, я спрашивал про "цену". Если у нас на родителе 2 обработчика - это ещё пол беды. Но если их будет 100500 образно говоря, не будет ли это слишком накладно по вычислительным мощностям и не будет ли это существенно стучать по производительности.
Не лучше ли в таком случае вешать обработчики через атрибуты, например, на дочерние элементы сразу? Или же можно не опасаться особо?

laimas 26.07.2017 14:54

Цитата:

Сообщение от GeekHacker
Но если их будет 100500 образно говоря, не будет ли это слишком накладно по вычислительным мощностям и не будет ли это существенно стучать по производительности.

Ну в общем-то и прямая установка обработчика не бесплатна и еще не известно, что более всего будет кушать в вашем приложении. )

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

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

GeekHacker 26.07.2017 16:02

Цитата:

Сообщение от laimas (Сообщение 459693)
Ну в общем-то и прямая установка обработчика не бесплатна и еще не известно, что более всего будет кушать в вашем приложении. )

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

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

Да, вы правильно поняли структуру страниц. Шапка и подвал фактически никогда не меняются. Речь идёт преимущественно о центральном блоке.
Проблема только в том, что вариантов страниц (подгружаемых центральных блоков) достаточно много.
При этом, назначать обработчики после подгрузки контента не хотелось бы. Ну типа подгрузить что-то, а потом куча условий, смотреть что же мы подгрузили и вешать обработчики.
Хотелось бы или повесить всё сразу, на все случаи жизни, но этот вариант достаточно прожорливый. Или через атрибуты. Но тут, как вы подметили, крайне неудобно сопровождать.
Просто думал может кто-то писал большие SPA-сайты, узнать какой подход выбрал. И какие впечатления, подводные камни.

GeekHacker 26.07.2017 16:06

Цитата:

Сообщение от Rise (Сообщение 459694)
Будет

Не лучше

Чем вас jQuery не устраивает?

jQuery устраивает полностью. Собственно, его и предполагается использовать. Вопрос же не в том, что использовать, а в том как использовать.
Просто изначально хотел построить всё на делегировании. А потом, мягко говоря, побоялся что будет слишком накладно.

laimas 26.07.2017 16:30

Цитата:

Сообщение от GeekHacker
Проблема только в том, что вариантов страниц (подгружаемых центральных блоков) достаточно много.

Ну это не критерий, ну вряд ли все и даже 3% элементов загружаемого будут требовать обработчиков. )

Я писал сайт для агентства недвижимости, в котором административный раздел весь асинхронный. Не смотря на массу задач раздела, множество сервиса, обслуживающий код небольшой и делегирований не масса. Часть однотипных задач определена объектом функций, запуск которых в том или ином случае определяет сервер (обмен в json), часть в виде плагинов, и т.п. Ведь не смотря на разнообразие задач, многие из них или узлы их, можно обобщить, определив один обработчик, а конкретизация внутри него определяется параметрами.

Не думаю, что и у вас, каждая страница будет требовать индивидуальности 100 процентной, да и не каждая вообще что-то будет требовать, разместили и на том спасибо. )

GeekHacker 26.07.2017 19:10

Цитата:

Сообщение от laimas (Сообщение 459734)
Часть однотипных задач определена объектом функций, запуск которых в том или ином случае определяет сервер (обмен в json), часть в виде плагинов, и т.п. Ведь не смотря на разнообразие задач, многие из них или узлы их, можно обобщить, определив один обработчик, а конкретизация внутри него определяется параметрами.

Ну и я решил вот практически таким путём пойти. Попробую, а там видно будет.
В любом случае, спасибо.


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