Учимся работать с jQuery шаблонами. Учимся работать с jQuery шаблонами Использование переменной $item
Лучший способ начать изучение шаблонов данных – это сразу же приступить к работе с ними. В показаны базовые возможности шаблонов. В этот листинг я включил полный HTML документ из-за способа, которым мы устанавливаем шаблоны, используя элемент script , но я покажу вам релевантные элементы в дальнейших примерах.
Листинг 12-3: Первый пример шаблона данных Example $(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 }, ]; }); ${name}: Jacqui"s Flower Shop Place OrderВ следующих разделах я разделю пример и объясню каждую часть. Если данные являются частью документа, они известны как встроенные данные . Альтернативой являются удаленные данные , это когда вы получаете данные от сервера отдельно от документа. Удаленных данных мы коснемся далее в этой главе, но это затрагивает поддержку jQuery для Ajax, что является темой глав 14 и 15.
Определение данныхНачальной точкой примера являются данные, которые в данном случае представляют собой массив объектов, каждый из которых описывает отдельную единицу цветочной продукции. В показаны соответствующие выражения из документа.
Листинг 12-4: Определение данных по цветам 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 }, ];Вы выражаете ваши данные как один или более JavaScript объектов. Библиотека шаблонов jQuery очень гибка, когда речь идет о виде объектов, которые могут быть использованы в качестве данных, но формат, показанный в шаблоне, используется наиболее часто, потому что он соответствует формату данных JSON, о чем я расскажу в главе 14.
Совет
JSON важен, потому что он часто используется с Ajax, о чем я расскажу в главах 14 и 15.
В этом примере массив содержит шесть объектов, каждый из которых имеет набор свойств, которые описывают продукцию цветочного магазина: отображаемое имя, имя продукта, размер запасов (имеющееся количество) и цену.
Определение шаблонаКак вы можете себе представить, в сердце библиотеки шаблонов данных находится шаблон данных. Это набор HTML элементов, содержащих метки-заполнители (placeholders), которые соответствуют аспектам объектов данных. В показан шаблон для этого примера.
Листинг 12-5: Определение шаблона данных ${product} .png" /> ${name} :Первая вещь, касаемо шаблона, на которую стоит обратить внимание, – это то, что он содержится внутри элемента script со значением атрибута type равном text/x-jquery-tmpl . Мы делаем это для того, чтобы браузер не интерпретировал содержание шаблона как обычный HTML. Это не совсем обязательно, но это хорошая практика, которая поможет избежать многих потенциальных проблем.
Вторым моментом, на который стоит обратить внимание, является то, что когда вы определяете шаблон в элементе script , вы назначите имя шаблона, используя атрибут id . В нашем случае шаблон называется flowerTmpl . Вам нужно знать имя шаблона, когда вы его применяете к вашим данным.
Содержание шаблона будет применяться к объектам в массиве данных, чтобы создать набор HTML элементов для каждого объекта в отдельности. Вы видите, что структура шаблона соответствует набору элементов, который я использовал для цветочной продукции в предыдущих главах. Ключевое различие, естественно, заключается в кусках кода, которые я выделил в листинге. Это и есть метки-заполнители для данных .
Когда библиотека шаблонов обрабатывает шаблон, она замещает любые метки-заполнители данных значениями свойств объекта, с которым работает. Так, например, первый объект в массиве библиотека шаблонов свяжет с меткой ${product} и заменит ее значением свойства единицы продукции, то есть в данном случае astor . Вот эта часть шаблона:
${product} .png"/>
трансформированная в это:
astor .png"/>
Вставка значений данных – это только одна из вещей, которые вы можете делать с шаблоном. Далее в этой главе я объясню другие возможности.
Применение шаблонаМы сводим шаблон, используя метод tmpl . Это позволяет указать данные, которые мы хотим использовать, и шаблон, который должен быть к ним применен. В показано использование этого метода.
Листинг 12-6: $("#flowerTmpl").tmpl(data).appendTo("#row1");Я использую jQuery $ функцию, чтобы выбрать элемент, который содержит шаблон, а затем для результата вызываю метод tmpl , передавая в качестве аргумента данные, которые вы хотите обработать.
Метод tmpl возвращает стандартный jQuery объект, который содержит элементы, полученные из шаблона. В нашем случае я завершаю это набором элементов div , каждый из которых содержит элемент img , label и input , которые были обработаны для одного из объектов в моем массиве данных. Я использую метод appendTo , что вставить полный набор дочерних элементов для row1 . Результат можно увидеть на .
Рисунок 12-2: Использование шаблона данных Настройка результатаМы не получили полностью того результата, который ожидали, потому что вся продукция расположена на одной линии. Но поскольку мы работаем с объектом jQuery , мы можем делать с элементами все, что мы и делали раньше. В показано, как это можно сделать, оперируя результатом метода tmpl .
Листинг 12-7: Обработка результатов, полученных из шаблона $("#flowerTmpl").tmpl(data) .slice(0, 3).appendTo("#row1").end().end().slice(3).appendTo("#row2"); }); ${name}:В этом примере я использую методы slice и end , чтобы сузить и расширить выборку, и метод appendTo , чтобы добавить подмножества элементов, сгенерированных из шаблона, в разные ряды.
Обратите внимание, что мне пришлось вызвать метод end два раза подряд, чтобы проработать сужение выборки, вызванное методами slice и appendTo . Это очень функционально, и я вообще люблю использовать метод end , чтобы создавать команды в одно выражение, но мне не очень нравится последовательность end().end() . Вместо этого я обычно разделяю такие последовательности на отдельные команды, как показано в .
Листинг 12-8: Разделение элементов с использованием нескольких выражений var templResult = $("#flowerTmpl").tmpl(data); templResult.slice(0, 3).appendTo("#row1"); templResult.slice(3).appendTo("#row2");В любом случае вы получаете тот же результат, то есть продукция поделена по двум рядам, в каждом содержится три цветка, как показано на.
Рисунок 12-3: Настройка результатов для того, чтобы они подходили версткеКорректировка ввода данных
Можно использовать и другой способ, чтобы скорректировать данные, переданные методу tmpl . В показано, как это можно сделать.
Листинг 12-9: Использование данных для корректировки результатов из шаблона $(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"); }); ${name}:В этом скрипте я решил задачу размещения цветов по рядам, используя шаблон дважды: по одному разу для каждого ряда. Я использовал метод slice , таким образом я смог передавать определенный набор объектов данных каждый раз шаблону. Техника отличается, но результат такой же, как и на .
Вычисление выраженийМы не ограничены исключительно значениями свойств объектов данных. Между фигурными скобками можно разместить выражение JavaScript, а движок шаблона произведет вычисления и вставит результат, сделанный шаблоном, в HTML. В содержится пример.
Листинг 12-10: ${name}:В этом шаблоне я использую тройной оператор JavaScript, чтобы установить атрибут value элемента input , основываясь на свойстве stocklevel . Я размещаю это выражение между фигурными скобками, так же как я делал, когда напрямую вставлял значения свойств. Если свойство stocklevel больше нуля, тогда атрибут value будет установлено на 1 , иначе оно будет равно 0 . Результат можно увидеть на . Для всех цветов, кроме пиона, значение stocklevel больше нуля.
Рисунок 12-4: Вычисление выражения в шаблонеЭтот пример вкратце демонстрирует основной функционал шаблона: вы комбинируете данные с шаблоном, чтобы получить объекты DOM, которые вы потом добавляете в документ, используя основной jQuery. Затем напрямую или косвенно можно использовать в выражениях значения данных, чтобы сгенерировать содержание.
С выпуском jQuery, жизнь разработчиков стала значительно проще. Например мы без труда можем сделать следующее:
$("#someElement").children().each(function() { $(this).wrap($("")); });
Этот код поместит всех потомков элемента с id #someElement в тег . В подобных операциях нет ничего плохого; это выражение абсолютно верно составлено и является очень удобным в некоторых ситуациях. Но HTML код, помещённый в наш сценарий - это нарушение структурной логики кода. В этом простом примере это нарушение не является существенным, однако в реальных проектах это очень распространено. Обычно подобный код содержит множество HTML фрагменты, которые выстраиваются в DOM после получения данных из AJAX запросов. Такой стиль может быстро превратиться в нечто, что будет крайне не читабельно.
Использование шаблонов позволит нам устранить этот недостаток, путём отделения HTML фрагментов от скриптов, таким образом разделить логику содержания разных видов кода. В процессе, я не могу не показать вам некоторые супер интересные нововведения, касающиеся AJAX, введённые jQuery 1.5.
НачалоВ этом примере мы будем разрабатывать Twitter виджет, который будет загружать не только наши самые последние сообщения, но и список друзей и последователей. Я выбрал Twitter для этого примера, потому что он взаимодействует с данными в формате JSON с которыми работать легко и весело.
Давайте же начнем; сам виджет будет построен на базе следующей HTML структуры:
jQuery, AJAX and Templating Dan Wellman
Husband, father, front-end developer and author. Writes for Nettuts and Packt Publishing. Works for @designhaus | jQuery fanatic
- Tweets
- Friends
- Followers
В этом примере мы используем HTML5. Для этого мы указали упрощенный DOCTYPE и элемент мета. Так же вы можете заметить в коде подключение к таблицам стилей, которые будут описаны через пару минут. В целях поддержки текущей версии IE8 и ниже, используем условные комментарии на специальный плагин html5shiv.
Используем asideВероятнее всего этот виджет, будет выглядеть как боковая панель, и отображать содержание указанного пользователя Twitter. Учитывая это, я решил поместить содержимое в тег . Для того чтобы с лёгкостью получить доступ к этому элементы выставим ему ID.
К слову о разметке. Все заголовки сообщений пользователя Twitter будут включены в тег , а изображение и всё остальное в теге
Вы можете изменить это на своё собственное предпочтение, когда будете реконструировать данный пример. Мы могли бы получить все необходимые данные через JSON, что мы и сделаем, однако, если в процессе загрузки возникнет задержка, посетителю будет отображено множество пустых блоков. Так что лучше нам дождаться полной загрузки и затем произвести заполнение блоков.
Ещё у нас на странице будут реализованы вкладки для переключения между списками сообщений, друзей и подписчиков. Все они будут заключены в теги
- ,
- и . Вкладка со списком сообщений будет отображаться по умолчанию, поэтому нам необходимо указать специальный класс CSS для активной вкладки. В более крупном проекте предпочтительнее использовать jQuery для переключения вкладок интерфейса, но я не хотел концентрировать внимание на этом, т.к. тема урока другая.
Наконец, у нас есть всё что нужно для того, чтобы разместить все входящие данные: внешний контейнер с ID, три вкладки для сообщений, друзей и последователей, которые также имеют свои ID для удобства выборки. Мы также добавили элемент для тех посетителей, которые не используют JavaScript при просмотре web-страниц. Обратите внимание, что мы будем использовать плагин tmpl, который даст нам возможность использовать шаблоны jQuery. Этот плагин можно скачать .
Чуть ранее я упомянул о специальных таблицах стилей. Откройте новый файл в вашем любимом текстовом редакторе и добавить следующий код:
#tweetbox { display:block; width:300px; padding:10px; border:1px solid #aaa; -moz-border-radius:5px; border-radius:5px; font-family:"Trebuchet MS", Arial, Helvetica, sans-serif; background-color:#eee; } #tweetbox img { display:block; } #user { margin-bottom:10px; float:left; } #user h2 { margin:0 0 10px 0; position:relative; font-size:18px; } #user img { float:left; } #user p { width:230px; margin:0; position:relative; float:left; font-size:10px; color:#333; } #user img { display:block; margin-right:10px; border:3px solid #333; } #tools { margin:0; *margin-bottom:-10px; padding:0; clear:both; list-style-type:none; } #tools li { float:left; } #tools a { display:block; height:20px; padding:3px 24px; border:1px solid #aaa; border-bottom:none; -moz-border-radius:5px 5px 0 0; border-radius:5px 5px 0 0; margin-right:-1px; position:relative; font-size:14px; outline:none; background-color:#d6d6d6; background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0.5, #E8E8E8), color-stop(0, #DBDBDB), color-stop(0.5, #D6D6D6)); background-image: -moz-linear-gradient(center top, #E8E8E8 50%, #DBDBDB 0%, #D6D6D6 50%); } a { text-decoration:none; color:#333; } #tools .on { height:21px; margin-top:-1px; top:1px; } #feed { width:298px; border:1px solid #aaa; clear:both; background-color:#d6d6d6; } #feed > div { display:none; } noscript { display:block; padding:10px; font-size:13px; color:#333; }
Сохраните этот файл как tweetbox.css в том же каталоге, где находятся ваши HTML страницы. Это лишь малое, что мы можем указать для дизайна нашего виджета. В коде, который мы только что привели, вы можете заметить несколько приёмов CSS3: округлённые углы (обратите внимание, мы больше не нуждаемся в -WebKit- для этих целей!), а так же некоторые градиенты для вкладок. Следует отметить, что мы прячем все блоки, за исключением одного - активного. На данный момент виджет должен выглядеть так:
Добавляем скриптТеперь давайте напишем небольшой скрипт для реализации переключения вкладок. Создайте новый файл и добавьте следующий код:
(function($) { //табы var tweetbox = $("#tweetbox"), tweetData = null, friendData = null, followData = null; tweetbox.find("#tools a").click(function(e) { e.preventDefault(); var link = $(this), target = link.attr("href").split("#"); tweetbox.find(".on").removeClass("on"); link.addClass("on"); tweetbox.find("#feed > div").hide(); tweetbox.find("#" + target).show(); }); })(jQuery);
Сохраните этот файл (tweetbox.js) в том же каталоге, где и всё остальное. Тут ничего сложного нет. Вкладки не является сутью урока, так что я не буду долго на этом останавливаться. Скрип работает следующим образом: мы используем анонимную функцию, которая отлавливает тот контейнер который является активным. Мы также инициализируем три переменные, которые будем использовать в дальнейшем. Выставляем их значение в null.
Выборка элементов будет проводиться неоднократно, так что не будет лишним закэшировать все это дело, что поможет свести к минимуму число jQuery запросов. Далее мы устанавливаем click обработчик на вкладки, которые не являются активными, и выставляем соответствующие классы для отображения стилей. Другими словами активную вкладку делаем неактивной, а одну из неактивных активной. Перед тем, как отобразить содержимое выбранной вкладки, мы скрываем их все и только потом выводим информацию.
Получаем данныеТеперь начинается самое интересное. Мы будем делать запрос на Twitter для того, чтобы получить данные для всех 3х вкладок, а так же применим плагин для того, чтобы иметь возможность использовать jQuery шаблоны. Добавьте этот код после предыдущего:
$.ajaxSetup({ dataType: "jsonp" }); function getTweets() { $.ajax("http://api.twitter.com/statuses/user_timeline/danwellman.json", { success: function(data) { var arr = ; for (var x = 0; x < 5; x++) { var dataItem = {}; dataItem["tweetlink"] = data[x].id_str; dataItem["timestamp"] = convertDate(data, x); dataItem["text"] = breakTweet(data, x); arr.push(dataItem); } tweetData = arr; } }); } function getFriends() { return $.ajax("http://api.twitter.com/1/statuses/friends/danwellman.json", { dataType: "jsonp", success: function(data) { var arr = ; for (var x = 0; x < 5; x++) { var dataItem = {}; dataItem["screenname"] = data[x].screen_name; dataItem["img"] = data[x].profile_image_url; dataItem["name"] = data[x].name; dataItem["desc"] = data[x].description; arr.push(dataItem); } friendData = arr; } }); } function getFollows() { return $.ajax("http://api.twitter.com/1/statuses/followers/danwellman.json", { dataType: "jsonp", success: function(data) { var arr = ; for (var x = 0; x < 5; x++) { var dataItem = {}; dataItem["screenname"] = data[x].screen_name; dataItem["img"] = data[x].profile_image_url; dataItem["name"] = data[x].name; dataItem["desc"] = data[x].description; arr.push(dataItem); } followData = arr; } }); } $.when(getTweets(), getFriends(), getFollows()).then(function(){ // используем шаблоны });
Сначала мы используем метод ajaxSetup() для того, чтобы указать формат данных, с которыми мы будем иметь дело - jsonp. Поскольку нам предстоит выполнить несколько запросов, лучше один раз указать данное значение.
Далее мы пишем 3 стандартные по функционалу метода, в которых используем отдельные метод ajax(). Он будет делать запрос на сервис Twitter и возвращать данные. Для запроса мы будем использовать специальные ключевые слова: user_timeline, friends и followers. Чтобы быть уверенными, что данные будут сформированы после удачного запроса, включим наш код в блок success. Каждая из этих функций будет возвращать по 100 хорошо упакованных объектов с Twitter данными.
Для крока нам не нужно такое количество данных, поэтому мы поместим в массив только по 5 объектов. Для того чтобы быть уверенными, что мы формируем JSON данные в правильном формате, ключи каждого элемента помещаем в двойные кавычки.
Данные функции практически идентичны друг другу. Заметьте, что для каждого запроса, мы используем свои уникальные ключевые слова. В конце работы каждой из функций, мы присваиваем скопленные массивы элементам, которые содержали значения null (сформированы выше).
Заметьте, что мы не просто вызываем наши три метода - а используем метод when(), который запустит своё содержание только тогда, когда эти три метода закончат свою работу. После того как все три функции вернут success, мы запустим метод then(), где будет располагаться функциональность, касающаяся шаблонов.
К слову сказать. В данном контексте можно указать и метод fail(), который запустится в том случае, если запросы на Twitter пройдут с ошибкой.
Всё это очень круто, поскольку в ранних версиях jQuery не был предусмотрен подобный функционал.
Вспомогательные функцииВ предыдущем примере мы используем некоторые вспомогательные функции convertDate() и breakTweet(). Вот их содержание:
//формат даты convertDate = function(obj, i) { if (window.ActiveXObject) { obj[i].created_at = obj[i].created_at.replace(/[+]\d{4}/, ""); } var days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], date = new Date(obj[i].created_at), formattedTimeStampArray = .created_at], date.toLocaleDateString(), date.toLocaleTimeString()]; return formattedTimeStampArray.join(" "); } breakTweet = function(obj, i) { var text = obj[i].text, brokenTweet = , atExpr = /(@[\w]+)/; if (text.match(atExpr)) { var splitTweet = text.split(atExpr); for (var x = 0, y = splitTweet.length; x < y; x++) { var tmpObj = {}; if (splitTweet[x].indexOf("@") != -1) { tmpObj["Name"] = splitTweet[x]; } else { tmpObj["Text"] = splitTweet[x]; } brokenTweet.push(tmpObj); } } else { var tmpObj = {}; tmpObj["Text"] = text; brokenTweet.push(tmpObj); } return brokenTweet; }
Функция convertDate(): в первую очередь проверяем, использует ли браузер window.ActiveXObject. Если да, то мы используем JavaScript метод replace(), чтобы удалить Timezone, которая содержится в JSON объекте, возвращённом от Twitter. Этот метод использует регулярные выражения для того чтобы найти и заменить строку.
Далее мы создаём некоторые переменные; массив, который содержит сокращённые названия месяцев. Дни в датах JavaScript начинаются с 0. Затем мы создаём объект Date, используя конструктор new Date(, и передаём дату, которая хранится в свойстве created_at объекта, переданного в функцию.
Создадим ещё один массив из 3х элементов: первый это день недели, второй - локализованная дата, третий - локализованное время. После формирования массива, мы его возвращаем.
Функция breakTweet() немого сложнее. Тут нам необходимо преобразовать обычный текст в JSON массив, в котором каждый элемент это объект, содержащий свойства Name или Text. Они будут использоваться в шаблоне. Сначала мы получаем текст из объекта, который вернул нам Twitter (передали его в функцию). Так же тут применяем регулярное выражение, которое отлавливает наличие @usernames.
Далее мы сканируем текст, чтобы найти имя пользователя; если оно присутствует, вытаскиваем его. У нас получается массив из текстовых значений. Проходимся по этому массиву, ищем тест содержащий символ @; Если данный символ присутствует, то записываем его с ключом Name. Остальной текст записываем с ключом Text. Сформированные объекты помещаем в массив.
Вот и всё. Мы только что сформировали объект, который можем передать в jQuery шаблон.
Работа с шаблономТеперь когда все необходимые данные сформированы, можем приступать к последней части нашего урока: шаблонам. Вернёмся к содержанию блока метода then(). Вставьте код внутри данного блока:
//применяем шаблоны tweetbox.find("#tweetTemplate").tmpl(tweetData).appendTo("#tweetList"); tweetbox.find("#ffTemplate").tmpl(friendData).appendTo("#friendList"); tweetbox.find("#ffTemplate").tmpl(followData).appendTo("#followList"); //показываем сообщения tweetbox.find("#tweets").show();
Тут я демонстрирую использование плагина tmpl(). В данном фрагменте мы передаём сформированные данные в шаблон, указывая какой элемент будет их принимать. Метод tmpl() вызывается для каждого элемента, которые мы ещё не создали. Так давайте добавим их.
Добавляем jQuery шаблоныСнова вернёмся к HTML. Первое что мы сделаем, добавим тег сразу же после пустого ul с id “tweetList”:
{{each text}} {{if Name}} {{tmpl(Name) "#atTemplate"}} {{else}} ${Text} {{/if}} {{/each}} ${timestamp}
${$item.data}jQuery шаблоны добавляются на страницу HTML непосредственно через элемент . У каждого такого элемента должен быть выставлен элемент id для того, чтобы они могли быть распознаны и обработаны методом tmpl(). Так же атрибут type должен хранить следующее значение - text/x-jquery-tmpl.
В первом шаблоне, мы добавляем структуру, которую в последствии хотим выводить в DOM. В частности каждое Twitter сообщение будет заключено в теги ,
И . Чтобы вставить данные из JSON объекта, переданного через метод tmpl(), мы используем серию шаблонных тегов. Затем используем {{each}} для того, чтобы пройтись по каждому элементу, которое хранится в массиве.
Это массив содержит все Twitter сообщения. Для каждого из них мы делаем проверку на наличие ключа Name. Если ключ присутствует, используем {{tmpl}} тег. Имя функции, через которую будут проходить данные, мы указываем в скобках после tmpl, а также указываем id шаблона, который будем использовать (более детально рассмотрим его через несколько минут). Если объект не содержит ключ Name, то значит мы имеем дело с обычным текстом, который вставим с помощью ${text}. Это условное достигается с помощью тега {{if}} и {{else}}. После этого мы должны закрыть условие, используя {{/if}, и аналогично завершить цикл {{/foreach}}.
Теперь нам необходимо создать ссылку, которая будет вести непосредственно на Twitter. Для этого используем ${tweetlink} как часть атрибута href, и свойство ${timestamp}. Это данные, которые мы создали и успешно обработали по запросу user_timeline.
Таким же образом нам необходимо создать вкладки для отображения наших друзей и подписчиков. Их мы создадим по точно такому же принципу. База для всех одна:
-
${screenname} ${desc}
Вот мы и научились передавать данные в шаблон с помощью json и выводить их при помощи конструкции ${data};
Последний штрихТеперь, когда почти всё готово, мы можем добавить еще несколько CSS стилей для того, чтобы всё это выглядело более менее прилично. Добавьте следующий код в конец файла tweetbox.css:
#feed ul { padding:0; margin:0; } #feed li { padding:0; border-bottom:1px solid #aaa; list-style-type:none; font-size:11px; } #feed li:last-child, #feed li:last-child p { border-bottom:none; } #feed p { padding:10px; margin:0; border-bottom:1px solid #eee; background-image:-webkit-gradient(linear, left bottom, left top, color-stop(0.48, #c2c2c2), color-stop(0.71, #d6d6d6)); background-image:-moz-linear-gradient(center bottom, #c2c2c2 48%, #d6d6d6 71%); } #feed p:after { content:""; display:block; width:100%; height:0; clear:both; } .tweet-link { display:block; margin-top:5px; color:#777; } .img-link { display:block; margin:4px 10px 0 0; float:left; } #feed .username a { font-size:14px; font-weight:bold; } #feed .bio { display:block; margin-top:10px; }
После сохранения файла, наше приложение будет выглядеть следующим образом:
Есть еще одна вещь, которую нам, вероятно, следует реализовать: на данный момент, наше форматирования не работает в IE, поскольку IE не дружит с методом split(). Чтобы устранить эту проблему, мы можем использовать превосходный JavaScript патч, созданный Steven Levithan. Он может быть загружен с: http://blog.stevenlevithan.com/archives/cross-browser-split. Подключим этот код с помощью условного комментария:
Этот код надо добавить непосредственно перед подключением файла tweetbox.js.
ЗаключениеВ этом уроке мы рассмотрели некоторые более продвинутые возможности шаблонов в jQuery. Мы познакомились с итерационным циклом {{each}} и условиями {{if}} и {{else}}.
Ключевым моментом является то, что новая система шаблонов в jQuery позволяет нам разделить наш код, перемещая все HTML фрагменты из файлов JS и обратно в HTML файл.
Некоторые могут возразить, что мы сейчас просто увеличиваем количество тегов на нашей странице.
Однако я думаю, что эта альтернатива более предпочтительна. Элементы в формате $ ("") просто строки (конечно же до того момента как браузер запустится, и они создадутся и вставятся в DOM).
Мы также посмотрели на новый метод when(), добавленный в JQuery 1.5, который позволяет управлять множеством асинхронных запросов. Далее мы использовали метод then(). Данная функция запустит своё содержание только после завершения всех асинхронных процессов.
Надеюсь, статья была для вас полезна. Спасибо за внимание.
Плагин для реализации сменяющихся слов с различными анимированными эффектами. CSS эффект подойдет для реализации промо-сайтов и анимированных баннеров.
Реализация разбиения содержимого страницы на вкладки (табы) с использованием анимированных CSS3 эффектов. Четыре варианта исполнения: горизонтальные и вертикальные табы с различными анимированными эффектами.
3. Адаптивный jQuery слайдер на основе плагина IMPRESS.JSКлассный слайдер с имитацией 3D эффекта при пролистывании слайдов. При увеличении/уменьшении размера экрана - изменяется размер шрифта, изображений и всех элементов на слайде, что гарантирует корректное отображение при любом расширении экрана. Предусмотрена автоматическая прокрутка.
jQuery решение для создания удобной навигации по разделам документа без перезагрузки страницы. Каждый раздел отображается в отдельном блоке с вертикальной прокруткой, а переход между ними можно осуществить как с помощью клика мыши, так и воспользовавшись заглавием (при большом расширении экранов содержание заглавие отображается с левой стороны, при просмотре сайта на малом экране - сверху документа).
Реализация навигации по содержимому в виде Список категорий → Список разделов → Содержимое раздела. Навигация сопровождается различными JS эффектами.
Пролистывание слайдов осуществляется с Parallax эффектом (движение слоев с различной скоростью, в совокупности создают 3D эффект). Размер слайдера изменяется пропорционально изменению размера окна браузера.
Слайд-шоу с музыкальным сопровождением. Есть возможность ставить на паузу или проматывать музыкальную композицию.
11. Своеобразное меню на jQuery и CSSПри выборе пункта меню область с его содержимым раскрывается поверх.
Выпадающее горизонтальное меню с интересным jQuery эффектом появления вложенных пунктов.
Обалденный jQuery CSS плагин, будет очень полезным дополнением для сайта любой веб-студии или фрилансера. С его помощью можно наглядно отобразить примеры выполненных работ с разбивкой по времени. Внизу отображается сама временная шкала, а сверху выполненные работы. Для перехода между работами можно использовать как шкалу, так и стрелки влево/вправо.
14. Галерея «TouchTouch», оптимизированная для просмотра с мобильных устройств 15. CSS3 слайдер изображений «Cycle Slider»При клике на название выезжает изображение с описанием. Используется только CSS3.
17. Классные яркие всплывающие подсказки jQuery и CSS3
Урок по созданию галереи .Всплывающие jQuery подсказки в 7 стилевых оформлениях. Легко подключить и использовать в своих проектах.
Если изображений в галерее больше 5, то появляются стрелки влево/вправо для навигации по фотографиям.
Слайдами могут быть не только изображения, но и другой HTML контент.
Плагин для создания фотореалистичных теней.
Свежая реализация слайдера.
26. Перенос текста «Bacon»Необычный эффект переноса текста на странице на новую строчку по кривой или заданной линии с определенным шагом смещения.
Плагин автоматически рассчитывает размер шрифта для каждого слова таким образом, чтобы весь текст занимал одинаковую область по ширине, вне зависимости от количества слов в строке.
28. Выбор вида отображения блоков с использованием CSS3Четыре вида отображения блоков: изображение с описанием в три колонки, изображение с описанием в одну колонку, только изображения, только текстовое описание. Для переключения вида отображения блоков необходимо воспользоваться пиктограммами сверху.
Он обеспечивает возможность использования шаблонов, упрощающих генерацию HTML-элементов из объектов данных JavaScript.
Чтобы не возникало недопонимания, хочу предупредить, что данный модуль не относится к числу активно разрабатываемых или поддерживаемых в настоящее время, и команда разработчиков jQuery не рекомендует его применять. Это не означает, что вы не должны его использовать, однако я счел своим долгом сказать вам об этом, прежде чем вы будете включать его в свои проекты. Я был бы рад порекомендовать вам какой-нибудь другой активно разрабатываемый вариант, однако найти хотя бы близкую по своим возможностям замену jQuery Templates мне пока что не удалось. Но даже при упомянутом отношении к нему разработчиков этот модуль все еще остается наилучшим.
История модуля jQuery Templates довольно необычна. В свое время Microsoft и команда разработчиков jQuery объявили, что трем подключаемым модулям, разработанным компанией Microsoft, присвоен статус "официальных", чего до того не удостаивался ни один из подключаемых модулей.
Спустя какое-то время команда jQuery объявила об отказе от использования этих модулей и лишении их статуса официальных, а также о своих планах относительно замены их другой функциональностью. Предполагаемая замена должна была войти в состав библиотеки jQuery UI. Прискорбно, но факт: ничего из того, что было обещано, пока еще не предоставлено, а отвергнутые плагины по-прежнему доступны и широко используются (особенно это относится к подключаемому модулю для работы с шаблонами).
Совершенно очевидно, что решение о том, использовать ли код, применение которого не рекомендовано, каждый принимает самостоятельно, но лично мне нравится функциональность, обеспечиваемая шаблонами, и я часто ее использую. При этом я исхожу из того, что могу в любой момент заглянуть в исходный код и устранить любую серьезную проблему, если она возникнет, а то, что иногда все-таки приходится искать обходные пути для преодоления незначительных затруднений, окупается выгодами, которые дает использование шаблонов.
Настройка библиотеки jQuery TemplatesПрежде чем использовать шаблоны jQuery, нужно загрузить библиотеку jQuery Templates и подключить ее к своему документу.
Распакуйте архив и скопируйте файл jQuery.tmpl.js (версия для разработки) или jQuery.tmpl.min.js (версия для развертывания) на свой веб-сервер. Следующее, что необходимо сделать - добавить в образец документа элемент script, подключающий библиотеку шаблонов, как показано в примере ниже:
Библиотека jQuery $(function() { // Сюда будет помещаться код примеров }); h1 { min-width: 70px; border: thick double black; margin-left: auto; margin-right: auto; text-align: center; font-size: x-large; padding: ..png"); background-size: contain; margin-top: 0; } .dtable {display: table;} .drow {display: table-row;} .dcell {display: table-cell; padding: 10px;} .dcell > * {vertical-align: middle} input {width: 2em; text-align: right; border: thin solid black; padding: 2px;} label {width: 6em; padding-left: .5em; display: inline-block;} #buttonDiv {text-align: center;} button {padding: 12px;} #oblock {display: block; margin-left: auto; margin-right: auto; min-width: 700px; } Цветочный магазин Заказать
Мы будем использовать этот код в качестве образца документа в этой статье. Наверное, вы заметили, что от первоначального варианта, рассмотренного ранее, он отличается не только тем, что в него добавлена библиотека шаблонов, но и тем, что из него удалены элементы, соответствующие различным видам цветочной продукции. Это сделано специально для того, чтобы мы могли восстанавливать эти элементы в документе различными способами с помощью библиотеки шаблонов.
Внешний вид исходного документа в окне браузера на данном этапе представлен на рисунке:
Простой пример шаблона данныхНаилучший способ изучения шаблонов данных - сразу же взяться за дело. Для демонстрации основных возможностей шаблонов мы используем код из примера ниже:
... $(function() { var data = [ { name: "Астра", product: "astor", stocklevel: "10", price: 2.99}, { name: "Нарцисс", product: "daffodil", stocklevel: "12", price: 1.99}, { name: "Роза", product: "rose", stocklevel: "2", price: 4.99}, { name: "Пион", product: "peony", stocklevel: "0", price: 1.50}, { name: "Примула", product: "primula", stocklevel: "1", price: 3.12}, { name: "Подснежник", product: "snowdrop", stocklevel: "15", price: 0.99}, ]; $("#flowerTmpl").tmpl(data).appendTo("#row1"); }); .png"/> ${name}: ...
В последующих разделах мы разобьем пример на отдельные части и проанализируем код каждой из них по отдельности. Когда данные являются частью документа, они называются встроенными данными (inline data) . Альтернативой им являются дистанционные данные (remote data) , хранящиеся на сервере отдельно от документа. Мы рассмотрим дистанционные данные несколько позже, а пока что можно заметить, что этот вопрос тесно связан с поддержкой Ajax, которую предоставляет библиотека jQuery.
Определение данныхПример начинается с определения данных. В нашем случае данные - это массив объектов, каждый из которых описывает отдельный вид цветочной продукции. Соответствующий фрагмент кода приведен ниже:
Var data = [ { name: "Астра", product: "astor", stocklevel: "10", price: 2.99}, { name: "Нарцисс", product: "daffodil", stocklevel: "12", price: 1.99}, { name: "Роза", product: "rose", stocklevel: "2", price: 4.99}, { name: "Пион", product: "peony", stocklevel: "0", price: 1.50}, { name: "Примула", product: "primula", stocklevel: "1", price: 3.12}, { name: "Подснежник", product: "snowdrop", stocklevel: "15", price: 0.99}, ];
Данные выражаются в виде одного или нескольких объектов JavaScript. Библиотека шаблонов jQuery предоставляет значительную гибкость в выборе объектов, которые могут быть использованы в качестве данных, но представленный выше формат, соответствующий формату данных JSON , является наиболее распространенным. Формат JS0N играет очень важную роль, поскольку его часто используют при работе с Ajax.
В этом примере массив состоит из шести объектов, каждый из которых имеет ряд свойств, описывающих конкретный продукт: отображаемое имя, имя продукта, имеющееся количество единиц товара и цена.
Определение шаблонаКак вы, наверное, и сами догадываетесь, центральным элементом библиотеки шаблонов является шаблон данных (data template) . Он представляет собой набор HTML-элементов, содержащих заполнители, которые соответствуют различным свойствам объектов данных. Шаблон для этого примера показан ниже:
.png"/> ${name}:
Первое, на что следует обратить внимание, - это то, что шаблон помещается в элемент script, атрибуту type которого присваивается значение несуществующего типа - text/x-jquery-tmpl . Это сделано для того, чтобы браузер не пытался интерпретировать содержимое шаблона как обычную HTML-разметку. Хотя это и несущественно, но такой практики следует придерживаться, поскольку она чрезвычайно полезна и позволит вам избежать множества потенциальных проблем в будущем.
Второй момент, на котором я хочу заострить ваше внимание, - это то, что для присвоения имени шаблону, определенному в элементе script, используется атрибут id. В данном случае именем шаблона служит flowerTmpl. Чтобы применить к данным шаблон, необходимо знать его имя.
Содержимое шаблона будет применено ко всем объектам в массиве данных, что приведет к созданию набора HTML-элементов для каждого объекта. Вы видите, что структура шаблона в целом соответствует набору элементов, которые использовались в предыдущих статьях для представления различных видов цветочной продукции. Главное, чем они отличаются - это элементы кода выполняющие функции заполнителей (data placeholders) .
В процессе обработки шаблона вместо каждого заполнителя подставляется значение свойства, взятое из текущего объекта. Например, для первого объекта массива вместо заполнителя ${product} будет подставлено значение свойства product, т.е. "astor". Таким образом, часть шаблона
${name}:
преобразуется в следующий HTML-фрагмент:
Астра:
Подстановка значений - не единственное, что могут делать шаблоны. Другие их возможности обсуждаются далее.
Применение шаблонаДля объединения шаблона с данными используется метод tmpl() . При этом вы указываете данные, которые должны использоваться, и применяемый к ним шаблон. Пример использования этого метода приведен ниже:
$("#flowerTmpl").tmpl(data).appendTo("#row1");
Здесь мы выбираем элемент, который содержит шаблон, используя для этой цели функцию $(), и вызываем для полученного результата метод tmpl(), передавая ему в качестве аргумента данные, которые хотим обработать.
Метод tmpl() возвращает стандартный объект jQuery, который содержит элементы, полученные из шаблона. В данном случае это приводит к набору элементов div, каждый из которых содержит элементы img, label и input, сконфигурированные для одного из объектов, содержащихся в массиве данных. Для вставки всего набора в качестве дочернего элемента в элемент row1 используется метод appendTo(). Результат представлен на рисунке:
Модификация результатаПолученный результат не совсем нас устраивает, поскольку все элементы, соответствующие различным цветам, отображаются в одном ряду. Но поскольку мы имеем дело с объектом jQuery, расположить элементы так, как нам надо, не составит большого труда. В примере ниже показано, как это можно сделать, воздействуя на результат работы метода tmpl():
... $("#flowerTmpl").tmpl(data) .slice(0, 3).appendTo("#row1").end().end() .slice(3).appendTo("#row2");
В этом примере методы slice() и end() используются для сужения и расширения набора выбранных элементов, а метод appendTo() - для добавления поднаборов элементов, сгенерированных с помощью шаблона, в различные ряды.
Обратите внимание: для возврата набора в исходное состояние, в котором он находился до применения методов slice() и appendTo(), метод end() пришлось вызывать два раза подряд. Ничего противозаконного в этом нет, и я охотно использую метод end(), чтобы выполнить необходимые действия в рамках одной инструкции, но последовательность end().end() не вызывает у меня восторга. В подобных случаях я предпочитаю разбивать всю последовательность действий на ряд отдельных операций, как показано в примере ниже:
Var templResult = $("#flowerTmpl").tmpl(data); templResult.slice(0, 3).appendTo("#row1"); templResult.slice(3).appendTo("#row2");
В обоих случаях результат будет одним и тем же: представление совокупности продуктов двумя рядами, в каждом из которых отображается по три вида цветов, как показано на рисунке:
Изменение способа предоставления входных данныхДругой возможный подход заключается в изменении способа передачи данных методу tmpl(). Соответствующий пример приведен ниже:
Var template = $("#flowerTmpl"); template.tmpl(data.slice(0, 3)).appendTo("#row1"); template.tmpl(data.slice(3)).appendTo("#row2");
В этом сценарии распределение элементов по рядам осуществляется путем двукратного использования шаблона - по одному разу для каждого ряда. Соответствующая часть объектов данных каждый раз передается шаблону с помощью метода slice(). Несмотря на отличие данного подхода от предыдущего, мы получаем тот же результат, который был представлен на рисунке выше.
Вычисление выраженийОбъекты данных можно использовать не только для получения значений свойств. Если поместить между двумя фигурными скобками выражение JavaScript, то движок шаблонов вычислит его и вставит в сгенерированную шаблоном HTML-разметку. Соответствующий пример приведен ниже:
${name}:
В этом шаблоне значение атрибута value элемента input устанавливается на основании значения свойства stocklevel с помощью тернарного условного оператора. Выражение, заключенное в фигурные скобки, играет ту же роль, какую играло бы записанное вместо него непосредственное значение свойства. Если значение свойства stocklevel больше нуля, то значение value устанавливается равным 1, в противном случае - 0.
Вид полученной страницы в окне браузера представлен на рисунке ниже. Значение stocklevel, большее нуля, установлено для всех цветов, кроме пионов:
Рассмотренный пример иллюстрирует основную схему работы с шаблонами: данные объединяются с шаблоном для получения DOM-объектов, которые затем добавляются в документ с использованием основной функциональности jQuery. Для генерации содержимого можно использовать как непосредственно заданные значения, так и вычисляемые выражения.
Использование переменных шаблонаШаблоны не являются сценариями JavaScript. Любое содержимое, которое вы добавляете в элемент script, считается частью шаблона и будет включаться в выходной результат. Чтобы сделать шаблоны более гибкими, вам предоставляется небольшое количество контекстных переменных, которые можно использовать в дескрипторах заполнителей. Краткое описание этих переменных содержится в таблице ниже:
Использование переменной $dataПеременная $data возвращает текущий элемент данных, к которому применяется шаблон. Например, используемая переменная $data будет поочередно ссылаться на каждый из объектов, соответствующих отдельным видам цветов. Для получения данных в предыдущем примере в шаблоне использовался тернарный условный оператор. Такой подход вполне допустим, однако чтение получаемых при этом шаблонов часто вызывает затруднения, чего, разумеется, желательно не допускать.
Я всегда стараюсь уменьшить объем кода шаблона до необходимого минимума и поэтому предпочитаю использовать переменную $data внутри функций JavaScript, которые затем вызываю из шаблона. Соответствующий демонстрационный пример приведен ниже:
$(function() { var data = [ { name: "Астра", product: "astor", stocklevel: "10", price: 2.99}, { name: "Нарцисс", product: "daffodil", stocklevel: "12", price: 1.99}, { name: "Роза", product: "rose", stocklevel: "2", price: 4.99}, { name: "Пион", product: "peony", stocklevel: "0", price: 1.50}, { name: "Примула", product: "primula", stocklevel: "1", price: 3.12}, { name: "Подснежник", 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; } .png"/> ${name}:
В этом примере определяется функция stockDisplay(), возвращающая значение, которое должно отображаться в элементе input. Аргументом этой функции является объект данных, который мы получаем внутри шаблона с использованием переменной $data. Учитывая, что речь идет всего лишь о простом тернарном операторе, разница в удобочитаемости кода по сравнению с предыдущим вариантом не очень значительна, но в случае более сложных выражений или в случае многократного использования выражения в пределах одного шаблона она будет гораздо более ощутимой.
Определяя функции, которые будут вызываться из шаблона, будьте внимательны. Дело в том, что такие функции должны определяться до вызова метода tmpl(). Я всегда стараюсь помещать их в конце элемента script, но если функция должна находиться внутри обработчика события ready, то непременно следует убеждаться в том, что она была ранее определена. Другой распространенной ошибкой является то, что функцию часто определяют внутри шаблона.
Использование функции $() внутри шаблонаВ применяемых внутри шаблона заполнителях можно использовать функцию $() библиотеки jQuery, однако при этом очень важно не забывать, что элементы, генерируемые посредством шаблона, не присоединяются к документу и поэтому не будут попадать в наборы выбранных элементов jQuery. Я редко использую указанную возможность, поскольку обычно меня в большей степени интересуют элементы и связанные с ними данные, которые я генерирую самостоятельно.
Использование переменной $itemОбъект, возвращаемый переменной $item, решает несколько задач. Первая из них - обеспечение возможности обмена дополнительными данными между сценарием JavaScript и шаблоном. Соответствующий пример приведен ниже:
$(function() { var data = [ { name: "Астра", product: "astor", stocklevel: "10", price: 2.99}, { name: "Нарцисс", product: "daffodil", stocklevel: "12", price: 1.99}, { name: "Роза", product: "rose", stocklevel: "2", price: 4.99}, { name: "Пион", product: "peony", stocklevel: "0", price: 1.50}, { name: "Примула", product: "primula", stocklevel: "1", price: 3.12}, { name: "Подснежник", product: "snowdrop", stocklevel: "15", price: 0.99}, ]; $("Специальное предложение на сегодняшний день: " + "скидка 50 центов") .insertAfter("h1") .css({ color: "red", fontSize: "14pt", textAlign: "center" }); 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"); }); .png"/> ${name}:
В этом примере мы создаем объект options, для которого определяются свойство (discount) и метод (stockDisplay()). Затем этот объект передается методу tmpl() в качестве второго аргумента. Доступ к свойствам и методам объекта из шаблона обеспечивает переменная $item. Как видите, для обработки скидки в цене, здесь используется свойство discount объекта options.
Хочу обратить ваше внимание на необходимость включения префикса $ в имена контекстных переменных: $item и $data. Такой же префикс обязателен и в конструкции дескриптора шаблона ${...}, используемой для подстановки значений в шаблон. Пропуск любого из этих префиксов является одной из наиболее распространенных ошибок.
О других применениях этого объекта мы поговорим далее.
Использование вложенных шаблоновПри создании сложных приложений иногда имеет смысл разбить большой шаблон на несколько частей, объединение которых происходит уже на стадии выполнения приложения. Как будет показано далее, такой способ объединения шаблонов обеспечивает более гибкое управление выводом. Мы начнем с самого элементарного. В примере ниже показано, каким образом один шаблон может ссылаться на другой:
... .png"/> ${name}: {{tmpl($data, $item) "#inputTmpl"}}
В этом примере шаблон разбит на две части. Первая из них, шаблон flowerTmpl, вызывается для каждого элемента массива данных. В свою очередь, этот шаблон вызывает шаблон inputTmpl для создания элементов input. Вызов второго шаблона осуществляется с помощью дескриптора {{tmpl}} . В этом вызове используются три аргумента. Первые два - это текущий элемент данных и объект options; эти аргументы заключаются в круглые скобки. Третий аргумент - это вызываемый шаблон. Его можно задавать либо jQuery-селектором (что и сделано выше), либо переменной или функцией, определенной в сценарии.
Использование условных шаблоновМеханизм шаблонов обеспечивает возможность динамического принятия решений относительно использования различных частей шаблона в зависимости от выполнения определенных условий. Для этого существуют дескрипторы {{if}} и {{/if}} , пример использования которых представлен в ниже:
... {{if stocklevel > 0}} .png"/> ${name}: {{/if}}
Условие указывается в дескрипторе {{if}}, и часть шаблона, заключенная между этим дескриптором и дескриптором {{/if}}, будет использоваться, только если результат вычисления условного выражения окажется равным true. Если же этот результат равен false, то указанная часть шаблона игнорируется. В данном случае проверяется значение свойства stocklevel, и если оно равно нулю, то игнорируется весь шаблон flowerTmpl. Это означает, что отображаться будут лишь те продукты, которые имеются в наличии на складе, как показано на рисунке:
Более сложные условия можно задавать с помощью дескриптора {{else}} , позволяющего определить часть шаблона, которая должна использоваться в тех случаях, когда результатом вычисления выражения в дескрипторе {{if}} является false. Соответствующий пример приведен ниже:
... {{if stocklevel > 5}} .png"/> ${name}: {{else stocklevel > 0}} .png"/> ${name}: (Небольшое количество) {{else}} .png" style="opacity:0.5"/> ${name} (Нет в наличии) {{/if}}
В этом сценарии отображаемый набор элементов определяется тем, сколько единиц товарной продукции того или иного вида имеется на складе: больше пяти, пять, меньше пяти или вообще нет в наличии. Я ввел лишь незначительные различия между элементами, генерируемыми для каждого из этих условий, но вы вправе применять эти возможности для генерации совершенно другого содержимого. Наконец, в случае необходимости можно вызывать по условию другие шаблоны.
Результат работы приведенного выше сценария представлен на рисунке: