Pull to refresh

Comments 33

Вообще, есть более удобный и наглядный префикс «js-*»
Угу, я его привел в пример сразу под заголовком третьего способа.
Зачем заморачиваться с классами, когда есть data-атрибуты? Ваши примеры выглядели бы у меня вот так:

$('*[data-app="skip-advert"]'); $('*[data-app="go-to-modern"]'); $('*[data-app="help-me"]');

Почти полностью исключается случайная стилизация.
Эта конструкция будет работать медленнее. Поскольку нет команд выборки по атрибутам.
Что вы имеете в виду?

document.querySelectorAll() - оно?
Согласен, медленнее.

Но тут вопрос не только в скорости, а и в удобстве, не так ли? Иначе надо везде юзать id, который ещё быстрее. Вот у меня ваш тест показал 36 тыщ операций в секунду при использовании jQuery и data, а сколько реально может быть нод на странице, которые будут обрабатываться скриптом? Ну пускай тыща. Если у вас не специфический проект, где нужна мега-скорость, то разницей в N миллисекунд ради удобства можно и пренебречь.

Или мы тут об абстрактных «попугаях» разговариваем?
Да, я с вами согласен. Я за любой способ, кроме первых двух. Атрибуты имеют столько же прав на существование, как и классы.
Разве что, несколько уменьшается читаемость и чистота, из-за дополнительных скобок и кавычек.
Я прошёл все способы, и ещё не упомянутый здесь атрибут role с удобным плагином для коротких селекторов по ролям.
Последние несколько проектов использовал .js-*, и поверьте это не менее удобнее чем любой другой способ. А главное back-end разработчики не теряются, так как в HAML-разметке это будет выглядеть так же лаконично, как в селекторах, без лишних знаков.
Более того, эта нотация рекомендована в гайдах гитхаба.
Кстати, может произойти обратное описанному в статье: верстальщик понавешает свои стили на классы .js-*. Поэтому вариант с role видится очень заманчивым
Так сравнение некорректное. Медленее, да, но не на столько, как показано в тесте.

Сравните.

getElementsByClassName возвращает HTMLCollection, а querySelectroAll возвращает NodeList. Это совершенно разные вещи и используются по-разному.
Плюс такой конструкции в том, что явно отделяется оформление от кода.
Data ничем не лучше классов. На data- в одном элементе может быть куча всего навешано, и ваш атрибут затеряется. А еще если кто-то заведет ваш data-app для своих целей?
Кто-то для своих целей может и должен использовать role, т.к. это атрибут, относящийся к семантике документа. В отличие от него атрибут data-app не несёт никакой семантической нагрузки и поэтому он лучше.
Такие ситуации крайне редки. К тому же мы можем писать так: role=''js-action''. Тогда мы точно никому мешать не будем. Плюс спецификация не запрещает использование множества role, так что если кому надо добавит свой role. А вот к вашему data-app свой data-app я добавить не могу. Конечно, это сферично в вакууме, но тем не менее.

А еще если я вызову var foo = bar.dataset, то в foo окажется data-app. При желании можно придумать пример, где это сломает логику работы приложения.
Надо обходиться без «если». Если не хотите превратить проект в басню «Лебедь, рак и щука», нужно вводить какие-то правила. Как пример: атрибут data-app используется для определения роли элемента (привязки событий, обращения к нему из js итд).
Хотелось бы отметить, что, когда мы просто пишем $('.app-skip-advert'), подразумевая, что выбрали при этом один-единственный элемент на странице, это мало чем отличается от использование id — в любом случае, при наличии двух элементов будут проблемы.

Мощь привязки по специальным классам проявляется при поиске соответствующих элементов в некотором контейнере. Так, $('#mainblock.app-skip-advert') защитит от появления такого же класса в соседнем блоке, а $('.app-skip-advert', block) позволит оперировать ссылкой внутри некоторого повторно используемого компонента страницы.
Верно. Может я непонятно написал, но в конце статьи есть:
При использовании нескольких шаблонов на одной странице, в случае если привязка идет не к глобальному объекту, а к корню шаблона, код будет работать хорошо.

Это я и имел ввиду.
Кроме того, вы, видимо, подразумеваете, что использовать один и тот же класс, для разных задач.
Скажем так — допускать использование одного и того же класса разными программистами для разных задач на одной странице.
А также для привязки событий к элементам можно создать маленький (ну или как получится) js-объект типа:

AdminList = {

  showFilter: function() {}

};


и к html-элементам просто применять навешивание:

<span onclick="AdminList.showFilter();">Фильтры</span>


В таком случае вообще не нужно искать, что/где/когда навешивалось на элемент — это сразу видно. Другой плюс — после перезагрузки такого html-блока аяксом, например, обработчик всегда сработает, чего не скажешь о часто встречающемся $('.class').click() на элементе (ну хоть live/on есть, что радует)…
Это, конечно, красиво и очевидно, когда нам нужно привязать одно событие к одному элементу. А если нужно привязать событие ко всем дочерним элементам (например, запрос результатов поиска по изменению значений в форме), если привязывать несколько событий к одному элементу, итд, то подобный способ ИМХО превращается в боль. После переименования функции при рефакторинге, опять же, переименовывать ее во всех шаблонах.
Переименовать функцию с современными-то IDE типа PhpStorm — гораздо легче, чем оперировать классами, на которые что-то навешено…
Если нужно привязать несколько событий к одному элементу — это изврат какой-то, но в любом случае сделайте обертку на этими несколькими действиями, из которой по очереди вызовите нужные…
Переименовать функцию с современными-то IDE типа PhpStorm — гораздо легче, чем оперировать классами, на которые что-то навешено…

Чем легче-то? В чем принципиальная сложность оперирования правильно составленными классами/ролями?

Если нужно привязать несколько событий к одному элементу — это изврат какой-то, но в любом случае сделайте обертку на этими несколькими действиями, из которой по очереди вызовите нужные…

Почему изврат-то? Нам нужно, например, обрабатывать клик по кнопке и обрабатывать наведение мыши, предположим. И превращается наш элемент из
<button class=".kill-all-humans-btn" data-tooltip="Dis button killz all humanz">Don't touch!</button>

в ужасное, на мой взгляд,
<button onclick="UsefulFunctions.killAllHumans" onmouseover="Tooltips.show('Dis button killz all humanz')" onmouseout="Tooltips.hide">Don't touch!</button>


В добавок, на класс можно навешивать не только события, но и поведение вообще. Т.е. к нему можно обращаться из js-кода.
Тоже использую такой метод, во всех местах, которые генерируются или потенциально могут меняться динамически.
Оказалось проще создать исчерпывающий набор функций, завернутых в объект, чем дергать из десятка разных мест различные инициализаторы биндингов.
С делегированием событий тоже как-то не срослось: навешивать различные обработчики 500 разных кнопок на один контейнер — это как-то совсем негуманно.
Кстати, ВКонтакте тоже использует onclick="..." в ленте.
Отличная, на мой взгляд, альтернатива специальным классам — роли и role.js.
как уже писали выше — пробовалось и в итоге для понимания бэкэндщиков было трудным, в тестах сложно искать по ролям, да и по скорости проигрывает классам вроде как
Бэкендщикам бэкендово, фронтендщикам фронтендово. Как вообще роли касаются бэкенда? Да и чем они сложнее для понимания, чем классы? При использовании Рельсы в Slim они добавляются гемом role-rails, в Haml — role-haml.
При тестах, опять таки, особых проблем замечено не было, особенно при использовании паттерна Page Object.
Ну а экономией миллисекунд скорости на фронте я лично не страдаю.
Уже не первый год для стилей использую классы вида «class-name», а для javascript — вида «jsClassName». При первом же взгляде на разметку можно понять, какие классы для чего созданы.
В проекте на работе нашел следующий код:

<a href="#" class="command-delete trash">Удалить в корзину</a>
<a href="#" class="command-delete permanent">Удалить навсегда</a>
<script>
$(function() {
    $('.remove').bind('click', function() {
        var action = $(this).prop('class').replace('command-delete ', '');
        SomeBackend.RemoveBook(id, action);
    });
});
</script>

После этого — только data-*.
class=«js-someAction» — для привязки событий, data-someProperty=«value» — для параметров, передаваемых в эти события. Так все логически разделено, а значит удобно, и свойства используются по прямому назначению.
У меня логика такая… если событие подразумевает «одноразовость» — т.е. для одного элемента и никак иначе, то привязываю по ID. Если одно и то же событие может быть вызвано с разных элементов (пусть даже с разными параметрами), то классы.
left, b_font, red_font — это ужасные имена CSS-классов. Не надо так.
Sign up to leave a comment.

Articles