May 23

Цель статьи - показать, что из себя представляет “ненавязчивый JavaScript”, для чего он нужен, и чем он лучше “навязчивого” JavaScript. В рунете я подобных статей не встречал (может они и есть, но мне на глаза не попадались и немного погуглив, я тоже ничего не нашел), а как показывает практика - очень многие не знают, что это такое и как этим пользоваться.

Что такое Unobtrusive JavaScript

Unobtrusive JavaScript - это техника программирования на языке JavaScript, которая состоит из следующих принципов:

  • разделения структуры (HTML) / оформления (CSS) и поведения (JavaScript)
  • использование JavaScript для повышения удобства использования уже рабочего приложения
  • применения техники Graceful degradation - если браузер не поддерживает те или иные функции, которые мы добавляем в приложение с помощью JavaScript - приложение всё равно остается рабочим

Зачем?

Это удобно, это практично, это легко реализуемо и это помогает Вам увеличить аудиторию вашего сайта за счет пользователей, пользующихся старыми браузерами, отключающими JavaScript, пользователей, которые пользуются интернетом с мобильных устройств.

Как?

Легче всего показать это на примере. За ним далеко идти не нужно - возьмем всеми любимый Хабрахабр:

<div class="text_comments"> 

  <div class="comment_item" style="margin-left: 0px;">

    <div class="service_text_comments_holder">
      <a href="http://fxposter.habrahabr.ru/" class="comments_nickname">fxposter</a>
      ...
    </div>

    <div class="comment_text">...</div>

    <div class="comments_reply">
      <div class="reply_word_holder" id="reply_link866650">(<a href="javascript:saw(866650);">ответить</a>)</div>

        <div style="display: none" id="reply866650">
        <!-- форма отправки комментария -->
      </div>

    </div>
  </div>
</div>

Это код комментариев, которые показываются на страничке о посте. Для наглядности ненужные фрагменты были убраны.

Что плохо в этом фрагменте кода?

  1. JavaScript идет вперемешку с HTML (<a href="javascript:saw(866650);">ответить</a>)
  2. У людей с отключенным JavaScript’ом ответить на комментарий не получится в принципе

Как его можно улучшить?

  1. Вынести “навешивание” событий в отдельный файл
  2. Сделать так, чтобы при отключенном JavaScript’е пользователь перебрасывался на отдельную страницу, где бы он мог ответить на выбранный комментарий

Сказано - сделано. Преобразуем HTML к следующему виду:

<div class="text_comments"> 

  <div class="comment_item" style="margin-left: 0px;">

    <div class="service_text_comments_holder">
      <a href="http://fxposter.habrahabr.ru/" class="comments_nickname">fxposter</a>
      ...
    </div>

    <div class="comment_text">...</div>

    <div class="comments_reply">
      <div class="reply_word_holder" id="reply_link866650">(<a href="reply.php?comment_id=866650" class="show_reply_form" id="show_reply_form_866650">ответить</a>)</div>

        <div style="display: none" id="reply866650">
        <!-- форма отправки комментария -->
      </div>

    </div>
  </div>
</div>

Как видите - я изменил тег <a> (присвоил ему “нормальный” href, добавил id и class). Теперь при нажатии на ссылку “ответить” пользователя будет перебрасывать на страницу ответа на выбранный вопрос. Этим я выполнил второй пункт в списке улучшений. Теперь давайте взглянем на первый пункт: для того, чтобы у пользователей, у которых включен JavaScript вместо редиректа выполнялось открытие формы под самим комментарием мне нужно выбрать все элементы с классом “show_reply_form” и каждому из них назначить на событие onclick функцию, которая бы “открывала” соответствующую форму.

Напишем соответствующую функцию:

function showForm(event) {
  var id = parseInt(this.id.replace('show_reply_form_', ''));
  saw(id);
  return false;
}

Она берет this.id (т.е. id текущего обьекта), убирает из него “фразу” “show_reply_form_“, тем самым получая номер элемента, который нам нужно открыть и вызывает функцию saw, которая присутствовала изначально в HTML-коде. Для того, чтобы не произошел редирект после клика на ссылку - функция возвращает false.

Осталось только связать эту функцию с нашими ссылками.

В jQuery это делается так:

$('.show_reply_form').click(showForm);

В PrototypeJS - так:

$$('.show_reply_form').each(function(element) {
  element.onclick = showForm;
});

После присвоения нашей функции элементу - this.id станет относится к id этого элемента (да, это “магия JavaScript” :) ).

Весь JavaScript-код теперь можно вынести в отдельный файл:

function showForm(event) {
  var id = parseInt(this.id.replace('show_reply_form_', ''));
  saw(id);
  return false;
}

window.onload = function(event) {
  $$('.show_reply_form').each(function(element) {
    element.onclick = showForm;
  });
}

Здесь мы вызываем “связывание” наших ссылок с функцией показа формы при событии window.onload (при загрузке страницы).

Таким образом я выполнил и первый пункт в списке улучшений.

Выводы

На мой взгляд, такое использование JavaScript, а именно - вынос всех функций на JS в отдельный файл и связывание этих функций с элементами страницы с помощью различных событий (здесь мы видели события window.onload и element.onclick) - это на данный момент - единственно правильное использование JavaScript.

Дерзайте, господа. :)

PS. Я прекрасно знаю, что можно использовать событие не window.onload, а DOMContentLoaded. Но я считаю, что для примера понятнее будет всё же использование window.onload.

written by fxposter \\ tags: ,

2 Pings to “Unobtrusive JavaScript”

  1. Мысли о Unobtrusive Javascript » Блог FX'а Says:

    […] мне Unobtrusive JavaScript May […]

  2. Pages tagged "unobtrusive" Says:

    […] tagged unobtrusiveOwn a WordPress blog? Make monetization easier with the WP Affiliate Pro plugin. Unobtrusive JavaScript saved by 5 others     ravenstar321 bookmarked on 06/01/08 | […]


12 Responses to “Unobtrusive JavaScript”

  1. 1. Steward Says:

    Ну раз уж техника Unobtrusive JavaScript – это техника программирования на языке JavaScript, которая состоит из следующих принципов:
    * разделения структуры (HTML) / оформления (CSS) и поведения (JavaScript)

    то и CSS из тегов долой :)
    да и всё ли так просто как кажется? например я вижу на странице следующий вызов: javascript:saw(‘f’) – ну это мелочи конечно…

    а ещё вам не кажется что такое скрытое присвоение обработчиков событий несколько усложняет понимание что же именно выполняется по ссылке?
    нет… модель MVC конечно никто не отменял – и пока это лучшее что придумало прогрессивное человечество, но без фанатизма пожалуй

    а ещё расскажите чем же технология Unobtrusive JavaScript отличается от MVC модели – вот только в данном контексте Model – HTML, View – CSS, Control – JavaScript – и если это одно и то же – зачем придумывать новое название?

    спасибо за внимание.

    Пы.Сы. да и вообще на хабре на странице куча ненужного кода… для каждого коментария приделана скрытая до поры до времени форма ответа – нафига – если можно её сгенерировать скриптом. Вот только конечно может поднятся крик – а если скрипт отключен…. но только я не поддерживаю такие мнения что надо подстраиваться под такую ситуацию – отключен скрипт – свободен :)…

  2. 2. Kallisto Says:

    Даже не знал что это технология..) [:|||||:]

  3. 3. Гвидон Маляров Says:

    на счет тэгов поддерживаю – всему свое место! css в файлах стилей, код в подключаемых js библиотеках. и нефик засорять html его и так как правило масса!

  4. 4. FX Poster Says:

    Steward
    то и CSS из тегов долой :)
    Я пишу про JS в данном случае.

    а ещё вам не кажется что такое скрытое присвоение обработчиков событий несколько усложняет понимание что же именно выполняется по ссылке?
    Я вижу в отдельном файле всю логику работы JS на всей странице. На мой взгляд, этого вполне хватает.

    нет… модель MVC конечно никто не отменял – и пока это лучшее что придумало прогрессивное человечество, но без фанатизма пожалуй

    а ещё расскажите чем же технология Unobtrusive JavaScript отличается от MVC модели – вот только в данном контексте Model – HTML, View – CSS, Control – JavaScript – и если это одно и то же – зачем придумывать новое название?
    А мы что-то кроме MVC знаем? :) MVC – это абсолютно не панацея и использовать этот паттерн для написания хороших и красивых приложений на самом деле отнюдь не обязательно.

    Model – HTML, View – CSS, Control – JavaScript
    Бред, JS не связывает HTML и CSS, а стоит в стороне (по крайней мере должен там стоять).

    Kallisto, Гвидон Маляров
    :)))

  5. 5. Ximik Says:

    Впринципе да, оно то так, но обычно впадлу выносить в отдельную функцию. Это ж надо ей название придумывать, параметры бррр

    P.S. А ты обоими CMF владеешь? Тогда может Prototype vs jQuery? Интересно будет почитать.

  6. 6. FX Poster Says:

    Ximik
    А стили в отдельный файл выносить не впадлу? :)

    А ты обоими CMF владеешь? Тогда может Prototype vs jQuery?
    Писать могу на обоих, может на прототипе не так эффективно, как на jQuery, но могу, естественно. Только для того, чтобы писать такого сравнения одного “владения” мало. Нужно хорошо поюзать как прототип, так и jQuery на реальных проектах, а потом делится впечатлениями.

    Вкратце – jQuery – это “вещь в себе”. Всё внутри одного обьекта, всё инкапсулировано и предполагается, что пользователь будет его использовать только так, и никак иначе. Причем у jQuery цель одна – работа с DOM (ajax – это как дополнение к DOM-модели).

    А прототип – это расширение стандартных возможностей JavaScript’а и, в частности, DOM-модели. Расширение почти всех стандартных классов (String, Array, и т.д.), дополнительные возможности выборки элементов с помощью CSS Selector’ов, та же работа с event’ами. Только всё это построено как расширение возможностей, а не как инкапсуляция работы через свой API.

  7. 7. GameNinja Says:

    С window.onload есть одна серьезная проблема – до того как событие “выстрелит” придется ждать загрузки всей страницы, в т.ч. графики и всякой мерзости типа кнопок-счетчиков, которые могут грузиться часами.

    Поэтому я обычно делаю инициализирующую все яваскрипт-дела функцию не обработчиком события onload, а просто вызываю ее, вставляя перед закрывающим тэгом конструкцию типа такой:
    <script type=”text/javascript”>site_init();</script>

  8. 8. Petro Says:

    Steward
    Unobtrusive JavaScript на то і називається unobtrusive щоб бути ненав”язливим. А фрази типу отключен скрипт – свободен як на мене звучать просто смішно. Якщо ви хочете зробити хороший сервіс то повинні зробити все для того щоб користувачу було зручно. А стосовно MVC, абсолютно згідний з FX Poster – брєд.

    Ximik
    Чесно кажучи в цьму випадку можна було обійтися і без назви функції, в JavaScript є класна штука – лямбда функції. Тільки не треба казати що вона ускладнює читанні програми. Як на мене писати код (особливо для проектів з відкритим кодом) для людей котрі не знають синтаксису немає змісту.

    GameNinja
    jQuery має класну штуку
    $(document).ready(function(){
    // Your code here…
    });
    Ось тут щось про це пишуть.

  9. 9. Nikita Says:

    Целиком и полностью поддерживаю эту технику. И CSS нужно выносить в отдельный файл. Мухи — отдельно, котлеты — отдельно.

    Эту технику нельзя назвать MVC, как уже сказал FX Poster, потому что JS не связывает HTML и CSS. Я бы назвал это SVA (Structure, View, Action).

    GameNinja, у jQuery есть хороший вариант:
    $(document).ready(function(){
    // Your code here
    });

  10. 10. Webber Says:

    Без скрипта всё равно сайт должен работать.

  11. 11. arxymond Says:

    использование метода селективного поиска элементов, это как вы сказали … тоже не панацея… в солидно больших проектах не посоветовал бы этот метод…
    я принимал участие в таком проект и как раз JS использовали по этому методу… (правда, не называли это не как :)… ), но в один прекрасный день, элементов для селективного поиска стало много, поисков селективных для разных event-ов тоже… и скрипт стал тормозить мягко говоря сильно… и нам пришлось искать методы по лучше селективного поиска элементов…

    так что переусердствовать с этим типом поиска не посоветовал бы…

    P.S.
    правда мы использовали prototype, не знаю как в других framework-ах этот самый поиск реализован…

  12. 12. FX Poster Says:

    Тормозит в каком месте? При загрузке страницы?

Leave a Reply