Pro jQuery
Адам Фриман
Использование переменных шаблона
Шаблоны не являются скриптами JavaScript. Предполагается, что любое содержание, которое вы вставляете в скрипт, будет частью шаблона и будет добавлено к результату, когда используется шаблон. Чтобы шаблоны были более гибкими, существует несколько контекстных переменных, которые можно использовать внутри тегов "заменителей" (placeholder). Они описаны в таблице 12-2, и я объясню их в следующих разделах.
Таблица 12-2: Контекстные переменные шаблона
Переменная | Описание |
$data |
Возвращает текущую единицу данных |
$item |
Возвращает текущую единицу шаблона |
$ |
Возвращает jQuery $ функцию |
Использование переменной данных
Переменная $data
возвращает единицу данных, к которой применяется шаблон. Например, в этой главе $data
будет устанавливаться поочередно для каждого объекта цветка. В предыдущем листинге я использовал в шаблоне тройной оператор. Это очень вполне приемлемая технология, но я считаю, что тут легко можно прийти к не читаемому шаблону, который может быть частью проблемы, которую мы хотим избежать.
Я стараюсь свести код в шаблоне к минимуму, а для этого я люблю комбинировать переменную $data
с возможностью вызова функций JavaScript изнутри шаблона. В листинге 12-11 представлен пример.
Листинг 12-11: Использование переменной $data
в шаблоне
<script type="text/javascript">
$(document).ready(function () {
var data = [
{ name: "Astor", product: "astor", stocklevel: "10", price: 2.99 },
{ name: "Daffodil", product: "daffodil", stocklevel: "12", price: 1.99 },
{ name: "Rose", product: "rose", stocklevel: "2", price: 4.99 },
{ name: "Peony", product: "peony", stocklevel: "0", price: 1.50 },
{ name: "Primula", product: "primula", stocklevel: "1", price: 3.12 },
{ name: "Snowdrop", product: "snowdrop", stocklevel: "15", price: 0.99 },
];
var template = $('#flowerTmpl');
template.tmpl(data.slice(0, 3)).appendTo("#row1");
template.tmpl(data.slice(3)).appendTo("#row2");
});
function stockDisplay(product) {
return product.stocklevel > 0 ? 1 : 0;
}
</script>
<script id="flowerTmpl" type="text/x-jquery-tmpl">
<div class="dcell">
<img src="${product}.png" />
<label for="${product}">${name}:</label>
<input name="${product}" data-price="${price}" data-stock="${stocklevel}"
value="${stockDisplay($data)}" required />
</div>
</script>
В этом примере я определил функцию stockDisplay
, которая создает значение, которое должно быть показано в элементе input
. Аргументом функции является объект данных, который я получаю внутри шаблона, используя переменную $data
. Если сравнить с простым тройным выражением, то разница в четкости минимальна, но вы можете себе представить разницу для более сложных выражений или когда выражение несколько раз используется в одном том же шаблоне.
Внимание
Нужно быть осторожным при определении функции, которая будет вызвана из шаблона. Если более конкретно, то функция должна быть определена прежде, чем будет вызван метод
tmpl
. Я стараюсь размещать такие функции внутри моего элементаscript
, но если вы хотите поместить ее внутри обработчика событияready
, убедитесь, что функция определена своевременно. Кстати, частой ошибкой является определение функции внутри шаблона.
Использование в шаблоне jQuery $ функции
На месте "заменителя" шаблона можно использовать jQuery $
функцию, но важно иметь ввиду, что элементы, которые вы генерируете через шаблон, еще не присоединены к документу, и поэтому ваша jQuery выборка их не коснется. Я редко использую эту возможность, потому что мой интерес, как правило, распространяется на элементы, которые я генерирую, и данные, которые стоят за ними, но в листинге 12-12 представлен простой пример.
Листинг 12-12: Использование в шаблоне jQuery $
функции
<script type="text/javascript">
$(document).ready(function () {
$("<h2>Today's special offer: <span id=offer data-discount='0.50'>"
+ "50 cents off</span></h2>")
.insertAfter('h1')
.css({ color: "red", fontSize: "14pt", textAlign: "center" });
var data = [
{ name: "Astor", product: "astor", stocklevel: "10", price: 2.99 },
{ name: "Daffodil", product: "daffodil", stocklevel: "12", price: 1.99 },
{ name: "Rose", product: "rose", stocklevel: "2", price: 4.99 },
{ name: "Peony", product: "peony", stocklevel: "0", price: 1.50 },
{ name: "Primula", product: "primula", stocklevel: "1", price: 3.12 },
{ name: "Snowdrop", product: "snowdrop", stocklevel: "15", price: 0.99 },
];
var template = $('#flowerTmpl');
template.tmpl(data.slice(0, 3)).appendTo("#row1");
template.tmpl(data.slice(3)).appendTo("#row2");
});
function stockDisplay(product) {
return product.stocklevel > 0 ? 1 : 0;
}
</script>
<script id="flowerTmpl" type="text/x-jquery-tmpl">
<div class="dcell">
<img src="${product}.png" />
<label for="${product}">${name}:</label>
<input name="${product}" data-price="${price - $('#offer').data('discount')}"
data-stock="${stocklevel}" value="${stockDisplay($data)}" required />
</div>
</script>
В этом примере я добавил в документ элемент h2
, который содержит элемент span
, и атрибут data-discount
этого элемента определяет скидку для цветочной продукции. В шаблоне я использую jQuery $
функцию, чтобы разместить элемент span
, и метод data
, чтобы прочесть значение атрибута (метод data
я объяснил в главе 8). Когда шаблон используется для генерации элементов, цена, указанная в каждом объекте данных, уменьшается с учетом суммы скидки.
Я включил этот пример для полноты картины, но есть много всего, что мне в нем не нравится. Во-первых, использование $
функции таким образом, обозначает, что я ищу по всему документу элемент span
для каждого объекта данных, который я обрабатываю, что является совершенно ненужным и чрезмерным. Во-вторых, я снова включаю в мой шаблон код, а этого как раз хотелось бы избежать. В-третьих, обработка этого в функции позволит мне абстрагироваться от способа, которым определяется цена из шаблона. Тем не менее, все это говорит о том, что вам нужно получить доступ к функции изнутри шаблона, и это может вполне соответствовать вашему стилю кодирования в отличие от моего.
Использование переменной шаблона
Объект, возвращенный переменной $item
, выполняет несколько функций, которые я поясню в этой главе. Первая функция – это предоставить вам средства для добавления дополнительных данных между вашим jQuery скриптом и шаблоном. В листинге 12-13 представлен пример. Для подробной информации о других способах использования этого объекта смотрите раздел "Управление шаблоном функциями обработки событий" далее в этой главе.
Листинг 12-13: Передача опций в шаблон при помощи переменной $item
<script type="text/javascript">
$(document).ready(function () {
$("<h2>Today's special offer: <span id=offer data-discount='0.50'>"
+ "50 cents off</span></h2>")
.insertAfter('h1')
.css({ color: "red", fontSize: "14pt", textAlign: "center" });
var data = [
{ name: "Astor", product: "astor", stocklevel: "10", price: 2.99 },
{ name: "Daffodil", product: "daffodil", stocklevel: "12", price: 1.99 },
{ name: "Rose", product: "rose", stocklevel: "2", price: 4.99 },
{ name: "Peony", product: "peony", stocklevel: "0", price: 1.50 },
{ name: "Primula", product: "primula", stocklevel: "1", price: 3.12 },
{ name: "Snowdrop", product: "snowdrop", stocklevel: "15", price: 0.99 },
];
var options = {
discount: $('#offer').data('discount'),
stockDisplay: function (product) {
return product.stocklevel > 0 ? 1 : 0;
}
};
var template = $('#flowerTmpl');
template.tmpl(data.slice(0, 3), options).appendTo("#row1");
template.tmpl(data.slice(3), options).appendTo("#row2");
});
</script>
<script id="flowerTmpl" type="text/x-jquery-tmpl">
<div class="dcell">
<img src="${product}.png" />
<label for="${product}">${name}:</label>
<input name="${product}" data-price="${price - $item.discount}"
data-stock="${stocklevel}" value="${$item.stockDisplay($data)}" required />
</div>
</script>
В этом примере я определяю объект с именем options
и определяю свойство (discount
) и метод (stockDisplay
). Затем я передаю этот объект в качестве второго аргумента методу tmpl
. Свойства и методы объекта доступны в шаблоне через переменную $item
. Таким образом, если я хочу прочесть значение свойства discount
, я делаю следующее:
${price - $item.discount}
а если я хочу вызвать функцию stockDisplay
, я делаю так:
${$item.stockDisplay($data)}
Вы можете увидеть, как я использовал свойство discount
в объекте options
, чтобы привести в порядок размер скидки, которую я до этого получил через jQuery $
функцию. Не то, чтобы я любил такой стиль кодирования больше, но сейчас я ищу в документе элемент span
только один раз.
Совет
Еще раз, обратите внимание, как я обращаюсь к переменным шаблона при помощи префикса
$
:$item
и$data
. Также обратите внимание, как выглядит все выражение, заключенное в${...}
, с которого мы начали главу. Это распространенная ошибка – опускать один или другой знаки доллара.