Pro jQuery

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. Также обратите внимание, как выглядит все выражение, заключенное в ${...}, с которого мы начали главу. Это распространенная ошибка – опускать один или другой знаки доллара.

или RSS канал: Что новенького на smarly.net