Pro jQuery

Pro jQuery

Адам Фриман

Использование вложенных шаблонов

Во время создания сложных приложений может быть полезно разделить общий шаблон на более мелкие секции и объединять нужные во время выполнения. Как вы увидите в дальнейших разделах этой главы, если использовать шаблоны таким образом, можно получить очень хороший и четкий результат. Мы начнем с основ, и в листинге 12-14 вы увидите, как можно обращаться из одного шаблона к другому.

Листинг 12-14: Вложенные шаблоны
<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>
		{{tmpl($data, $item) "#inputTmpl"}}
	</div>
</script>

<script id="inputTmpl" type="text/x-jquery-tmpl">
	<input name="${product}" data-price="${price - $item.discount}"
		data-stock="${stocklevel}" value="${$item.stockDisplay($data)}" required />
</script>

В этом примере я разделил шаблон на два. Первый шаблон, flowerTmpl, вызывается для каждой единицы (предмета) в массиве данных. Этот шаблон вызывает шаблон inputTmpl, чтобы создать элемент ввода. Можно вызвать другой шаблон, используя тег {{tmpl}}, например, вот так:

{{tmpl($data, $item) "#inputTmpl"}}

При использовании тега {{tmpl}} есть три аргумента. Первые два – это единица данных, которую нужно обработать, и объект options; и они размещены в круглых скобках, как вы видите. Третий аргумент – это шаблон, который нужно использовать. Он может быть выражен как селектор (как у меня) или доступен через переменную или функцию, определенную в скрипте.

Использование вложенных шаблонов для массивов

Если вы передали во вложенный массив единственное значение или объект, тогда указанный шаблон используется только один раз, как в предыдущем примере. Но если же вы передаете массив объектов, тогда шаблон используется для генерирования элементов для каждой единицы массива, как показано в листинге 12-15.

Листинг 2-15: Использование вложенного шаблона для массива
<script type="text/javascript">
	$(document).ready(function () {
		var data = [
		{
			rowid: "row1",
			flowers:
				[{ 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 }]
		},
		{
			rowid: "row2",
			flowers:
				[{ 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 }]
		}];
		
		$('div.drow').remove();
		$('#rowTmpl').tmpl(data).appendTo('div.dtable');
	});
</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="${stocklevel}" required />
	</div>
</script>

<script id="rowTmpl" type="text/x-jquery-tmpl">
	<div id="${rowid}" class="drow">
		{{tmpl($data.flowers) '#flowerTmpl'}}
	</div>
</script>

Чтобы продемонстрировать эту возможность, я сделал рефакторинг объекта данных, таким образом, это сейчас массив, который содержит два объекта. Каждый из этих объектов определяет rowid, который используется как идентификатор ряда, и массив из трех объектов, представляющих цветочную продукцию.

Я удалил из документа элементы div для рядов, а затем использовал шаблон rowTmpl, чтобы обработать данные. Этот шаблон генерирует замену для этих элементов div для моей табличной CSS-верстки, а затем использует тег {{tmpl}}, чтобы обработать массив с объектами для цветов, вот так:

<script id="rowTmpl" type="text/x-jquery-tmpl">
	<div id="${rowid}" class="drow">
		{{tmpl($data.flowers) '#flowerTmpl'}}
	</div>
</script>

И хотя я вызвал шаблон только один раз, движок шаблона использует его, чтобы генерировать элементы для каждой единицы массива; это обозначает, что в конце для каждого цветка будет создан элемент в ячейке.

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

Листинг 12-16: Проведение рефакторинга встроенных данных для использования вложенных шаблонов
<script type="text/javascript">
	$(document).ready(function () {
		var originalData = [
			{ 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 itemsPerRow = 4;
		var slicedData = [];

		for (var i = 0, j = 0; i < originalData.length; i += itemsPerRow, j++) {
			slicedData.push({
				rowid: "row" + j,
				flowers: originalData.slice(i, i + itemsPerRow)
			});
		}

		$('div.drow').remove();
		$('#rowTmpl').tmpl(slicedData).appendTo('div.dtable');
	});
</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="${stocklevel}" required />
	</div>
</script>

<script id="rowTmpl" type="text/x-jquery-tmpl">
	<div id="${rowid}" class="drow">
		{{tmpl($data.flowers) '#flowerTmpl'}}
	</div>
</script>

В этом примере я разместил элемент по рядам, я затем передал отформатированный объект данным методу tmpl. Число единиц в каждом ряду определяется значением переменной itemsPerRow, которое в этом примере я установил на 4. Результат можно увидеть на рисунке 12-5.

Рисунок 12-5: Форматирование данных для шаблона

В определенной степени я просто усложняю весь документ. Я либо форматирую данные, либо принимаю более сложный шаблон. Мне кажется, этого не избежать, потому что движок шаблона делает все возможное, чтобы нам помочь. Корректный баланс между сложностью кода и сложностью шаблона зависит от формата данных, с которым мы работаем. Мой совет заключается в том, чтобы вы играли с кодом и пробовали различные подходы, пока вы не достигнете чего-то, что вам понравится, что будет понятным для других людей и чтобы вы были уверены в том, что сможете его поддерживать в будущем.

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