Назначение обработчиков и SPA
Доброго времени.
Нужен совет от гуру. Сразу скажу, что с web-разработкой знаком давно. Но что касается webА, то работал преимущественно с php. На js тоже успешно пишу, но не считаю его основным языком. Так что белых пятен хватает. Задача следующая: требуется написать сайтик, но сайт должен представлять собой SPA. Никаких перезагрузок страниц, всё исключительно на ajaxЕ со всеми вытекающими и т.д. Стоит отметить, что предполагается достаточно большое количество страниц. На каждой странице большое количество элементов взаимодействия с пользователем: ссылочки, кнопочки, формочки... Страницы, как правило, неоднотипные. Т.е. каждая страница, кроме пары блоков, не похожа на любую другую. И тут меня начинают мучать сомнения. Как же наиболее эффективно организовать назначение обработчиков на события. Рассматривается два варианта. Первый.. Делегирование. На какой-то общий элемент (контейнер) навесить все обработчики. Второй.. Навешивать обработчики через атрибуты элементов. Всегда придерживался правила не смешивать html и js. С этой позиции делегирование представляется более правильным. Но не будет ли это слишком накладно в данном конкретном случае? Ведь когда внутри контейнера у нас произойдёт, скажем, клик, то у нас же запустятся все обработчики данного события на контейнере. А их будет много. Вариант с атрибутами кажется менее накладным, но как-то и нравится меньше. Менее красиво что ли... В общем, готов выслушать мнение сообщества. Заранее благодарю. |
Цитата:
|
ну почему же? Есть два элемента с 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 всё разруливать, но это вообще не вариант. Т.к. логики будет много и там запутаться можно будет. |
Цитата:
|
Ну хотябы потому, что в данном случае мы вешаем на один элемент два обработчика события click. Разве нет? Запустите код из примера и посмотрите сами.
|
<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> Проверяйте, у каждого элемента будет свой обработчик, хотя делегируют они его одному родителю. При делегировании будет определяться источник события, в этом вся соль. |
А я разве утверждаю обратное?
Но если уж придираться к мелочам, то у дочерних элементов вообще нет обработчиков. Все обработчики мы вешаем на родителя. И срабатывают они на родителе. и при возникновении события сработает их столько, сколько мы их повесили на родителя. А вся эта магия с делегированием работает исключительно благодаря тому, что события могут всплывать по структуре DOM. и что в объекте события нам доступен реальный источник события. Разница между target и currentTarget. event.target - элемент на котором произошло событие и от которого оно начало всплытие. event.currentTarget - элемент, на котором сработал обработчик события. Я специально не стал использовать в примере какие-либо библиотеки типа JQuery, т.к. получается менее наглядно. Берите мой пример и при помощи контрольной переменной смотрите сколько было срабатываний обработчиков при клике на любом из дочерних элементов. |
Цитата:
В голове что-то не укладывается. Хрен с ним, пусть будет так: $a = [ 'a' => function() {}, 'b' => function() {} ] Если $a['b'](), то означает ли, что при этом будет выполнено и $a['a']()? А почему при щелчке по Span должен выполняться и обработчик А? О чем речь? |
GeekHacker,
доперло что не нравится - цена метода? |
А причём тут дочерние?
Речь о том, что событие возникает на родителе. С этим вы же спорить не будете? Всплытие ведь. А на родителе у нас висит два обработчика. Вот они и срабатывают. Ещё раз, берите мой пример и смотрите как работают обработчики. Какое сообщение мы получим в алерте и каким станет значение x после клика на любом потомке. |
Точнее не событие срабатывает на родителе, а событие всплывает до родителя, на котором срабатывают обработчики.
Да, именно, я спрашивал про "цену". Если у нас на родителе 2 обработчика - это ещё пол беды. Но если их будет 100500 образно говоря, не будет ли это слишком накладно по вычислительным мощностям и не будет ли это существенно стучать по производительности. Не лучше ли в таком случае вешать обработчики через атрибуты, например, на дочерние элементы сразу? Или же можно не опасаться особо? |
Цитата:
Если схематично представить, что шапка и подвал, это постоянные элементы, а бокс содержимого принимает асинхронный контент, то уже получение нового содержания не требует делегирования, а в загруженном можно при загрузке установить обработчики. При этом некую часть обработчиков, какие-то общие для всех страниц операции на загружаемых страницах можно делегировать. То есть если все распределить рационально, то таких сумасшедших количеств делегирований вряд ли будет. Если через атрибуты, ну в некоторых случаях может и быть, но как правило, вряд ли это удобно для сопровождения кода. Я так полагаю. |
Цитата:
Проблема только в том, что вариантов страниц (подгружаемых центральных блоков) достаточно много. При этом, назначать обработчики после подгрузки контента не хотелось бы. Ну типа подгрузить что-то, а потом куча условий, смотреть что же мы подгрузили и вешать обработчики. Хотелось бы или повесить всё сразу, на все случаи жизни, но этот вариант достаточно прожорливый. Или через атрибуты. Но тут, как вы подметили, крайне неудобно сопровождать. Просто думал может кто-то писал большие SPA-сайты, узнать какой подход выбрал. И какие впечатления, подводные камни. |
Цитата:
Просто изначально хотел построить всё на делегировании. А потом, мягко говоря, побоялся что будет слишком накладно. |
Цитата:
Я писал сайт для агентства недвижимости, в котором административный раздел весь асинхронный. Не смотря на массу задач раздела, множество сервиса, обслуживающий код небольшой и делегирований не масса. Часть однотипных задач определена объектом функций, запуск которых в том или ином случае определяет сервер (обмен в json), часть в виде плагинов, и т.п. Ведь не смотря на разнообразие задач, многие из них или узлы их, можно обобщить, определив один обработчик, а конкретизация внутри него определяется параметрами. Не думаю, что и у вас, каждая страница будет требовать индивидуальности 100 процентной, да и не каждая вообще что-то будет требовать, разместили и на том спасибо. ) |
Цитата:
В любом случае, спасибо. |
Часовой пояс GMT +3, время: 13:22. |