Еще в марте 2005 года (вскоре после того, как Джесси Джеймс Гаррет породил термин AJAX ), Rails был, вероятно, первой платформой, которая представила встроенную поддержку AJAX: Сэм Стефенсон написал теперь знаменитую библиотеку Prototype и вместе с Дэвидом включил вспомогательные методы в Rails ActionView. Затем он назывался JavaScriptHelper, который впоследствии был подвергнут рефакторингу и разделен на 3 отдельных помощника — JavaScriptHelper , PrototypeHelper и ScriptaculousHelper . Несомненно, ранняя и тесная интеграция возможностей AJAX в инфраструктуру была одной из замечательных USP Rails, которая помогла подтолкнуть его туда, где он сейчас.
AJAX на рельсах
Грубо говоря, PrototypeHelper предоставляет вам способы создания AJAX-форм, ссылок, кнопок и т. Д. Более конкретно, он использует базовые элементы HTML и добавляет к ним соответствующие атрибуты ( onclick , onsubmit и т. Д.). В 2005 году это был приемлемый способ (но даже тогда, он не был достаточно хорош), в то время как в настоящее время считается действительно плохой вещью смешивать JavaScript в вашем HTML. Люди называют это навязчивым JavaScript . Это плохо, потому что, как и в случае с MVC, проблемы должны быть разделены: HTML создает базовую структуру страницы, CSS обеспечивает стиль и макет, а JavaScript добавляет некоторое поведение поверх всего остального. Везде, где возможно, следует избегать смешения этих трех (хорошим примером исключения из этого правила будет включениестиль: «не отображать: нет;» в некоторых тегах, потому что некоторые браузеры не понимают это правильно, если это не встроенный стиль). Это также плохо, потому что это делает рефакторинг настоящим кошмаром (если вы не очень тщательно программируете — и давайте признаем это: кто на самом деле тщательно кодирует с помощью JavaScript? ;-)).
Эта статья будет первой из нескольких, посвященных теме, как заставить ваше веб-приложение использовать мощь ненавязчивого JavaScript. Это в основном введение в тему — мы начнем с простых, а более сложные темы AJAX будут описаны в следующих статьях. Также обратите внимание, что эта первая часть не относится к Rails и может применяться практически для любого веб-сайта, который вы можете разработать.
UJS4Рейлы и lowpro
Некоторые люди осознали проблему с встроенным JavaScript Rails и сделали что-то с этим: Дэн Уэбб начал проект UJS4Rails, который предоставлял вспомогательные методы для использования его библиотеки Proprotype lowpro в Rails. Он дошел до того, что сказал, что link_to_remote и другие удаленные функции, которые создают встроенный JavaScript, должны быть удалены из ядра Rails (не могу найти ссылку прямо сейчас — есть у кого-нибудь под рукой?).
Тем не менее, UJS Rails, как оказалось, не соответствовали планам Дэна по lowpro, поэтому он был отброшен и в течение некоторого времени не обслуживался. Тем не менее, lowpro активно разрабатывается и может использоваться довольно эффективно для удаления JavaScript из HTML.
Встречайте Event.addBehavior
Ключевой особенностью lowpro является метод с именем addBehavior, который добавляется в класс Event . Давайте посмотрим, как может выглядеть вызов addBehavior в вашем application.js . Мы добавим простую функцию ролловера:
Event.addBehavior({
// expects image names to be in the following format: some_image.extension
'img.rollover:mouseover': function(event) {
src = this.src.split(/\./); // split main part and extension
parts = src.first().split(/_/);
if(parts.last() != 'over') {
parts.push('over');
this.src = [ parts.join('_'), src.last() ].join('.');
}
},
'img.rollover:mouseout': function(event) {
src = this.src.split(/\./); // split main part and extension
parts = src.first().split(/_/);
if(parts.last() == 'over') {
parts.pop();
this.src = [ parts.join('_'), src.last() ].join('.');
}
}
});
Это в основном разделяет атрибут src тега image на несколько частей и проверяет, завершена ли последняя часть. Это небольшое соглашение по настройке: при его использовании у меня обычно есть две иконки, например add_product.png и add_product_over.png . Прежде чем я покажу вам, как использовать его в своем HTML, стоит упомянуть две вещи:
- Внутри поведения это относится к элементу, с которым связано событие, в данном случае к изображению.
- Поведения применяются к селекторам в стиле CSS. В приведенном выше примере мы добавляем поведение ролловера к каждому изображению, имеющему ролловер класса CSS . Событие прилагается в конце после двоеточия и Опуская на (так onsubmit становится подать , и т.д.). Если вы не укажете событие, поведение будет применено к ссылочным элементам, когда DOM будет готов (мы будем использовать это в следующем примере и во многих последующих статьях).
Чтобы использовать функцию ролловера, вы должны иметь что-то вроде следующего в вашем HTML:
<img src="/images/icons/ok.png" class="rollover" />
Довольно просто, а? Никакой JavaScript не загромождает ваш HTML — просто старый HTML с небольшим определением класса CSS. Я бы соврал, если бы сказал, что это невозможно без использования lowpro. На самом деле, только с самим Prototype вы можете получить ту же функциональность с немного меньшим количеством кода:
$$('img.rollover').each(function(element) {
src = element.src.split(/\./); // split main part and extension
parts = src.first().split(/_/);
element.observe('mouseover', function(event) {
if(parts.last() != 'over') {
parts.push('over');
element.src = [ parts.join('_'), src.last() ].join('.');
}
});
element.observe('mouseout', function(event) {
if(parts.last() == 'over') {
parts.pop();
element.src = [ parts.join('_'), src.last() ].join('.');
}
});
});
Так зачем использовать lowpro, если он заставляет вас использовать больше кода вместо меньшего? Моя причина проста: в этом случае (и во многих других) я предпочитаю ясность, а не просто краткость. Чистый способ Prototype — по крайней мере, на мой взгляд — фокусируется на элементе, тогда как подход lowpro подчеркивает поведение элемента, добавляя элемент к самому селектору. Вам придется выяснить для себя, какой стиль вы предпочитаете, и в этом случае — я обещаю, что будет более чем достаточно причин использовать lowpro в следующем эпизоде этой серии.
Ненавязчивый и доступный!
В любом случае, давайте рассмотрим более сложный пример. Мы хотим создать необычную форму, которая не использует ярлыки, а помогает пользователю, написав имя поля внутри текстовых полей и текстовых областей. Кроме того, мы хотим убедиться, что пользователи, у которых отключен JavaScript, все еще могут обрабатывать форму (когда-либо слышали о Accessibility и Progressive Enhancement ? Я, безусловно, на это надеюсь!). Давайте сначала посмотрим на JavaScript:
Event.addBehavior({
'label.text': function(e) {
this.hide();
},
'input[type=text], textarea': function(e) {
label = this.previous('label').innerHTML;
this.addClassName('with_label');
(this.tagName.toLowerCase() == 'input') ? this.value = label : this.innerHTML = label;
},
'input[type=text]:focus, textarea:focus': function(e) {
label = this.previous('label').innerHTML;
if(this.value == label) {
this.removeClassName('with_label');
(this.tagName.toLowerCase() == 'input') ? this.value = '' : this.innerHTML = '';
}
},
'input[type=text]:blur, textarea:blur': function(e) {
label = this.previous('label').innerHTML;
if(this.value.blank()) {
this.addClassName('with_label');
(this.tagName.toLowerCase() == 'input') ? this.value = label : this.innerHTML = label;
}
}
});
Wooha — здесь все немного сложнее …
Наши первые два блока кода не используют селектор событий — это означает, что они применяются к соответствующим элементам, как только сработает dom: загружен . Сначала мы скрываем все метки с помощью class = «text» . Во-вторых, мы выбираем все текстовые поля (обратите внимание на селектор CSS3!) И текстовые области, читаем их метки, добавляем их в качестве их значения / innerHTML (в зависимости от атрибута tagName мы решаем, является ли это текстовым полем или текстовой областью) и добавляем Имя класса CSS with_label .
Последние два блока кода обрабатывают выбор / отмена выбора текстовых полей и текстовых областей. Мы хотим убедиться, что пользовательский ввод сохраняется — это то, что еслипункты для: Когда выделено, очищайте текстовое поле / область, только если текст равен тексту метки, если размыто, восстанавливайте текст метки, только если поле пустое. Кроме того, мы добавляем / удаляем класс with_label по мере необходимости. Если вы хотите, вы также можете удалить пробелы из полей, используя strip () .
Давайте посмотрим на HTML:
<form action="/products" method="post">
<p>
<label class="text" for="product_name">Name</label>
<input id="product_name" name="product[name]" size="30" type="text" />
</p>
<p>
<label class="text" for="first_name">First name</label>
<textarea id="product_description" name="product[description]"></textarea>
</p>
<p>
<input id="product_submit" name="commit" type="submit" value="Create!" />
</p>
</form>
Здесь ничего особенного не происходит — мы определяем форму с двумя элементами (текстовое поле для названия продукта и текстовая область для описания) и соответствующие им метки.
Интересная вещь возникает при просмотре страницы в браузере: как и предполагалось, ни одна из меток не существует, и оба поля формы имеют соответствующее значение метки в качестве своего содержимого. Если вы нажмете на одно из полей, оно будет очищено. Если вы оставите поле без изменения его значения, значение будет сброшено до текста метки.
Другая интересная вещь происходит , когда вы отключите JavaScript в вашем браузере (довольно легко , если вы используете Firefox с Chris Pederick в большом Web Developer Toolbar — просто нажмите Отключить >> Javasript >> Всех JavaScript): Вдруг появляются ярлыки, и элементы формы больше не несут своих значений! Таким образом, деактивация JavaScript в значительной степени приводит к выводу, который вы ожидаете получить из приведенного выше фрагмента HTML: мы только скрыли метки и записали их значения в соответствующие им элементы с помощью JavaScript, поэтому никакой JavaScript не означает никаких действий.
предстоящий
Вот и все для первой части серии. Я знаю, что два примера, которые я показал, на самом деле не показывают, почему стоит хорошо взглянуть на lowpro. Тем не менее, я использовал их в качестве примеров, чтобы познакомить вас с синтаксисом и основными способами использования lowpro. В следующей части серии, которую я опубликую через несколько дней (она все еще нуждается в некоторой любви), я покажу вам, как использовать lowpro более эффективно, чтобы вы увидели, насколько он хорош на самом деле.
Что вы думаете?
Позвольте мне услышать ваше мнение о lowpro и ненавязчивых скриптах JavaScripts. Я также хотел бы услышать от людей, которые используют lowpro и хотели бы поделиться своим опытом.
Лицензия
Эта статья лицензирована в соответствии с лицензией Creative Commons Attribution для некоммерческих акций . Если вы хотите использовать эту статью способами, запрещенными этой лицензией, пожалуйста, свяжитесь со мной и спросите моего разрешения.