22 декабря 2015
2 июля 2009
16
Прогрессивное улучшение в JavaScript
Всем привет из армии, а точнее с военных сборов ;-)
Сегодня мы продолжим наш давний разговор про прогрессивное улучшение. Напомню, что до этого мы рассматривали теорию прогрессивного улучшения и ее приложение к HTML и CSS. В этой статье мы будем говорить о JavaScript, а точнее рассматривать фреймворк jQuery.
Дело в том, что я очень часто наблюдаю совершенно страшные конструкции скриптов (год назад я писал так же), которые, во-первых, тормозят сайты, а во-вторых, очень неудобны в использовании и работе. В этой статье я хочу показать, как делать не нужно и почему, а заодно привести примеры хорошего грамотного кода.
Ликбез
Итак, думаю вы помните, что суть прогрессивного улучшения состоит в слудующем:
- доступность и семантичность верстки;
- внешние стили и скрипты;
- верстка, стили и скрипты выступают отдельными «слоями», которые накладываются один на другой, а не смешываются как коктейль.
Внешние файлы стилей и скриптов позволяют работать с ними намного эффективнее и быстрее, чем с инлайновыми — их можно включать по необходимости в документы одной строкой, а не копипэйстом (стили мы уже рассмотрели), соответственно редактирование намного проще и быстрее.
«Слойность» позволяет, опять же, проще и правильнее работать с ними: например, переход с одного фреймворка на другой (или с одного дизайна на другой) делается заменой файлов, а не копанием во всех шаблонах с целью найти инлайновый стиль или привязанное событие. Кроме того, при командной разработке верстальщик и фронт-энд девелопер не будут мешать друг другу и их работа будет быстрее и проще.
Подключение скриптов
Мы уже много раз говорили о том, что файлы скриптов нужно подключать в самом низу страницы, а не вверху рядом со стилями. Это существенно уменьшает время загрузки страницы, так как браузер не ждет их загрузки до рендера, она происходит в самом низу.
Вот плохой пример подключения и выполнения клиентских скриптов:
...
<link rel="stylesheet" href="typo.css"/>
<script type="text/javascript" src="huge-file.js"></script>
</head>
<body onload="runMyScripts();">
...
А вот хороший:
...
<script type="text/javascript" src="huge-file.js"></script>
<script type="text/javascript" src="init.js"></script>
</body>
</html>
Файл init.js запусткает необходимые скрипты и может выглядеть как-то так (обычно запускаемых функций намного больше):
$(document).ready(function() {
runMyScripts();
});
Привязка функций
Часто разработчики делают вот такие вещи. Им кажется, что прописать событие или функцию непосредственно в HTML-коде страницы быстрее и правильнее, но это не так. Этим они только усложняют жизнь себе, другим разработчикам, пользователям и браузеру, создавая лишний код. Кроме того, если у вас всего одна привязка событий, то это еще не так смертельно, но если нужно сделать 30 одинаковых привязок, то от копипэйста могут заболеть пальцы.
Итак, плохой пример:
<a href="#" onclick="runMyFunc(this);" class="onclickLinks">ссылка №1</a>;
<a href="#" onclick="runMyFunc(this);" class="onclickLinks">ссылка №2</a>;
...
<a href="#" onclick="runMyFunc(this);" class="onclickLinks">ссылка №N</a>;
А вот это уже хороший:
$('a.onclickLinks').each(function() {
this.click(function(e) {
runMyFunc($(e.target));
});
});
Количество кода не меняется от количества таких ссылок, плюс они в принципе не завязаны друг на друга, так что процесс редактирвания занимает намного меньше времени.
Замечу так же, что этот принцип относится не только к привязке событий, но и к любому другому вызову функций. Помните: верстка отдельно, JavaScript отдельно. Не мешайте их в одну кучу.
Работа со стилями
Представим себе, что необходимо у какого-то блока поменять шрифт на жирный, цвет на красный и сделать прерывистую обводку в 3 пиксела толщиной. Все это нужно сделать при каком-то там клике на чем-то. Первое решение, которое приходит на ум, это прописать все это добро через стили прямо из JavaScript. И многие делают именно так (это плохо):
<script type="text/javascript">
...
$('#someDiv').css({
'font-weight': 'bold',
'color': '#990000',
'border': '#000 3px dotted'
});
...
</script>
Это кошмар. Во-первых, это неудобно, так как если вы захотите (или скажет дизайнер) сменить цвет (то есть часть стиля), то менять его вы будете внутри JavaScript (программная часть) — не логично, не так ли? Так что лучше завести для этого отдельный класс — при смене визуалки логика не будет затронута, только стили. Делать лучше вот так:
<style>
.someClass {
font-weight: bold;
color: #990000;
border: #000 3px dotted;
}
</style>
...
<script type="text/javascript">
...
$('#someDiv').addClass('someClass');
...
</script>
Вывод: разделяем стили и клиентскую логику, не мешаем JavaScript и CSS.
Итак, думаю, что этой статьей я смог убедить вас в том, что следования принципам прогрессивного улучшения помогают писать более правильный, удобный и красивый код. Если есть, что добавить, то комментарии к вашим услугам.
Особенно ценно последнее замечание по изменению стилевых свойств элемента непосредственно в js коде. Это ведёт к не меньшей неразберихе и негибкости, чем интеграция js в html-код.
1. Сначала создать структуру документа (xhtml)
2. Затем описать представление с помощью стилей (css + images)
3. В конце добавить интерактивность (javascript)
На каждом этапе, нужно вносить минимум изменений в уже реализованные слои. При этом, на каждом шаге сайт (страница) должен полностью работать.
Думаю, вам стоило бы рассказать про разделение логики в javascript на внешний вид и поведение подробнее.
Например, знаете ли вы, почему в xhtml strict запретили аттрибут target? Все потому, что ребята хотят отделить поведение (javascript) от внешнего вида (css) и описания (xhtml) документа.
Вот про это я бы почитал - может бы что-то новое для себя открыл :)
А так просто лень самому писать у себя. Трудно выдавить из себя текст :)
Тут вы не совсем правы. Дело в том, что на выборку селекторов тоже будет тратиться время, а иногда и очень много времени. Например, на странице 500 комментариев и надо привязать к каждому комменту (какому-то его блоку) несколько событий. В таком случае - выборка всех сенлекторов может занять много времени, поэтому возникает как бы эффект подвисания браузера. (Особенно это ярко выражено в случае FF и IE)
а не проще ли так?
- уведомление о совершенном действии (обычно AJAX): появляется с ярким фоном (дабы обратить внимание), а затем затухает в обычный фон
- удаление элемента (либо затухание в нулевую прозрачность, либо свертывание по высоте)
Лично я для реализации таких вещей не знаю способов, отличных от воздействия на конкретные css-свойства блоков. Если кто-то подскажет, буду признателен (Методы animate, toggle, fadeIn и fadeOut не предлагать, потому что это по сути те же манипуляции с конкретными css-свойствами).
http://docs.jquery.com/UI/Effects/ClassTransitions
Вобщем спасибо, хороший пост.
runMyFunc($(this));
});[/quote]
Тогда вообще так:
$('a.onclickLinks').click(runMyFunc); И в runMyFunc использовать указатель this.
Кстати, в статье неправильно - при использовании each ссылка this ведет на DOM-объект, а не его jQuery версию.
- если там идут одни определения функций, то нужно загрузить их до использования, соответсвенно, чем раньше - тем лучше. А head у нас - самый первый.
- если там непосредственно в теле идет что-то типа document.write(...), то скорее всего это генерируется текст для вывода - значит, вероятнее всего, помещать нужно в body.