Мастер-классы по Javascript, AJAX/COMET, jQuery Узнать больше...
Javascript.RU

Шаблонизация с javascript

http://ejohn.org/blog/javascript-micro-templating/

Есть одна утилитка, которой я уже пользуюсь некоторое время, довольно полезная при построении javascript-приложений. Это - супер-простая и очень быстрая функция для шаблонизации на клиенте. Она предложена Джоном Ресигом.

Я применяю ее для постраничной навигации и для небольших шаблонов в AJAX-приложениях с подгрузкой данных с сервера.

Вот исходный код функции шаблонизатора:

(function(){
  var cache = {};
 
  this.tmpl = function tmpl(str, data){
    // Выяснить, мы получаем шаблон или нам нужно его загрузить
    // обязательно закешировать результат
    var fn = !/\W/.test(str) ?
      cache[str] = cache[str] ||
        tmpl(document.getElementById(str).innerHTML) :
     
      // Сгенерировать (и закешировать) функцию, 
      // которая будет служить генератором шаблонов
      new Function("obj",
        "var p=[],print=function(){p.push.apply(p,arguments);};" +
       
        // Сделать данные доступными локально при помощи with(){}
        "with(obj){p.push('" +
       
        // Превратить шаблон в чистый JavaScript
        str
          .replace(/[\r\t\n]/g, " ")
          .split("<%").join("\t")
          .replace(/((^|%>)[^\t]*)'/g, "$1\r")
          .replace(/\t=(.*?)%>/g, "',$1,'")
          .split("\t").join("');")
          .split("%>").join("p.push('")
          .split("\r").join("\\'")
      + "');}return p.join('');");
   
    // простейший карринг(термин функ. прог. - прим. пер.)
    // для пользователя
    return data ? fn( data ) : fn;
  };
})();

Её можно использовать с шаблонами, написанными в таком виде (не обязательно точно в таком, но этот стиль мне нравится):

<script type="text/html" id="item_tmpl">
  <div id="<%=id%>" class="<%=(i % 2 == 1 ? " even" : "")%>">
    <div class="grid_1 alpha right">
      <img class="righted" src="<%=profile_image_url%>"/>
    </div>
    <div class="grid_6 omega contents">
      <p><b><a href="/<%=from_user%>"><%=from_user%></a>:</b> <%=text%></p>
    </div>
  </div>
</script>

Вы также можете сделать скриптовую вставку:

<script type="text/html" id="user_tmpl">
  <% for ( var i = 0; i < users.length; i++ ) { %>
    <li><a href="<%=users[i].url%>"><%=users[i].name%></a></li>
  <% } %>
</script>
<script type="text/html">

Скрипты с неизвестным типом содержания type (как в примере выше - браузер не знает что делать с text/html-скриптом) просто игнорируются браузерами и поисковиками.

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

А вызов шаблонки из скрипта - примерно такой:

var results = document.getElementById("results");
results.innerHTML = tmpl("item_tmpl", dataObject);

Вы можете прекомпилировать результат для дальнейшего использования. Если Вы вызываете функцию-шаблонизатор только с ID(или кодом шаблона) - она вернет прекомпилированную функцию, которую Вы можете запускать, когда угодно:

var show_user = tmpl("item_tmpl"), html = "";
for ( var i = 0; i < users.length; i++ ) {
  html += show_user( users[i] );
}

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

Однако, он использует одну технику, которая мне очень нравится - а именно: если Вы делаете поиск-и-замену фиксированных подстрок, то быстрее всех с этим справляется .split("match").join("replace").

Это неочевидно, но так оно работает быстрее всего в большинстве современных браузеров.

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


Автор: Илья Кантор, дата: 19 августа, 2008 - 11:42
#permalink

Чуть не забыл - когда шаблоны пишете - обязательно везде ставить точки с запятой и не использовать комментов //

Т.к весь шаблон функция превращает в одну строку в итоге - будут синтаксические ошибки без точек с запятой.

Эту шаблонку можно по-разному модифицировать, я использую чуть упрощенный вариант:

function tmpl(str){
    var fn = new Function("obj",
        "var p=[],print=function(){p.push.apply(p,arguments);};" +

        // Introduce the data as local variables using with(){}
        "with(obj){p.push('" + document.getElementById(str).innerHTML
          .replace(/[\r\t\n]/g, " ")
          .split("<%").join("\t")
          .replace(/((^|%>)[^\t]*)'/g, "$1\r")
          .replace(/\t=(.*?)%>/g, "',$1,'")
          .split("\t").join("');")
          .split("%>").join("p.push('")
          .split("\r").join("\\'") + "');} return p.join('');");


    return fn
}

Вызвать компиляцию шаблона и тут же получить результат для data можно так:

tmpl('template-id')(data)

Автор: Вирь (не зарегистрирован), дата: 25 сентября, 2008 - 13:14
#permalink

А разве нельзя в шаблонах использовать комменты следующего вида?

/* comment */

Мне кажется, что после сборки в одну строку комментарий такого вида не должен мешать выполнению скрипта, к тому же, можно удалять его через всё тот же RegExp... (с чем у меня, правда говоря, проблемы - пока не возникало большой необходимости его изучать)


Автор: Илья Кантор, дата: 26 сентября, 2008 - 17:41
#permalink

Угу, такой комментарий вполне подойдет.


Автор: И.Тынгылчав (не зарегистрирован), дата: 9 октября, 2008 - 10:34
#permalink

Извините, конечно, но это семиколесный велосипед. Его много раз изобретали до вас. И он конечно ездит. Но недалеко.
Есть куча js-фреймворков, превращающих маниуляции с DOM в детскую игру. Есть XSLT выполняемый непосредственно броузеорм или через JS. И в конце концов есть куча бесплатных или очень дешевых хостингов с php/.NET/phyton...


Автор: Илья Кантор, дата: 10 октября, 2008 - 15:10
#permalink

Вещь хорошая ездит замечательно. Пользуюсь нравится.
Про php/.NET/python - это Вы в сторону далеко ушли. Тут именно JS-шаблонка. Для своих задач. Возможно, их у Вас пока не возникало, возникнут - вспомните, придете на эту страничку

P.S А XSLT на уровне браузера - мало того что куча несовместимостей, так оно еще и убогое, без EXSLT.


Автор: vicont (не зарегистрирован), дата: 21 ноября, 2008 - 11:17
#permalink

для чего вообще это нужно?


Автор: Марианна (не зарегистрирован), дата: 24 декабря, 2008 - 13:25
#permalink

взял ваши примеры реализовал все работает гладко, мне понравилось


Автор: Алик Кириллович, дата: 15 февраля, 2009 - 20:35
#permalink

Эта функция шаблонизации не будет работать в ASP-страницах.

Дело в том, что дескрипторы начала (<%=) и конца (%>) шаблона уже зарезервированы ASP-движком.


Автор: Илья Кантор, дата: 12 апреля, 2009 - 19:29
#permalink

Точно. На таких страницах лучше бы поправить <%= .. %> на что-нибудь другое.. Например, на <?= ... ?>


Автор: Антоннн (не зарегистрирован), дата: 12 апреля, 2009 - 18:58
#permalink

А как сделать, чтоб при нажатии на кнопку появлялось окошко с текстом?(что надо в скрипте написать?)
(что надо здесь написать?)("действие")


Автор: GE1serf, дата: 22 января, 2010 - 15:33
#permalink

Спасибо за информацию.
Вопрос, не могу решить куда поместить шаблон, когда он необходим при реализации плагина/библиотеки...
Не хочется каждый раз копи-пастить шаблон в новый проект, где будет использоватся библиотека...


Автор: MODist, дата: 22 января, 2010 - 17:54
#permalink

Присоединяюсь к последнему вопросу. Если у меня многострочный шаблон, использующийся в двух-трех разных местах. Какие способы организации хранения и получения шаблонов?


Автор: Илья Кантор, дата: 22 января, 2010 - 23:09
#permalink

Это уже вопросы к вашему движку и фреймворку. Javascript-шаблон - такой же шаблон как и остальные.


Автор: cooli0, дата: 29 января, 2010 - 07:39
#permalink

Удивился по поводу сказанного, что split.join работает быстрее replace.

Поэтому провел тесты.

Делал замену 10 различных значений {blahblah} в длинной строке.
Запускал в IE6 и FF3.5. Оба браузера показали преимущество функции replace. Если в FF (на маленьких итерациях) значения еще хоть куда не шли, - похожие, то в IE6 split.join работает в разы медленнее replace. На больших итерациях split.join проигрывает очень сильно и в FF, и в IE6.


Автор: rmaksim (не зарегистрирован), дата: 8 марта, 2010 - 12:49
#permalink

а еще можно выкинуть лишнее - функция print нигде не используется, видимо ресиг юзал её для своих целей, потом забыл выкинуть её, а все остальные тупо содрали
print=function(){p.push.apply(p,arguments);}


Автор: Shoorf (не зарегистрирован), дата: 16 июня, 2010 - 17:17
#permalink

Функция print далеко не лишняя! Вставка переменной в шаблон осуществляется либо с помощью конструкции <%=variable%>, либо <% print (variable) %>. Второй вариант удобен в случае, например, такого шаблона:

<script type="text/html" id="my_tpl">
  <% if (something == true) print(variable) %>
</script>
var data = new Object();
data.something = true;
data.variable = "Привет!";
var dest_container = document.getElementById("dest_container");
dest_container.innerHTML = tmpl("my_tpl", data);

Автор: Shoorf, дата: 16 июня, 2010 - 17:26
#permalink

Неплохо было бы указать назначение функции print в статье.


Автор: pixmaster (не зарегистрирован), дата: 15 апреля, 2010 - 20:10
#permalink

пример с шаблонизатором сделанный на основе выше предложенного ссылка на архив


Автор: ixth, дата: 13 августа, 2010 - 13:07
#permalink

У меня почему-то не работает, просто возвращает id темплейта - и все.


Отправить комментарий

Приветствуются комментарии:
  • Полезные.
  • Дополняющие прочитанное.
  • Вопросы по прочитанному. Именно по прочитанному, чтобы ответ на него помог другим разобраться в предмете статьи. Другие вопросы могут быть удалены.
    Для остальных вопросов и обсуждений есть форум.
P.S. Лучшее "спасибо" - не комментарий, как все здорово, а рекомендация или ссылка на статью.
Содержание этого поля является приватным и не предназначено к показу.
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Разрешены HTML-таги: <strike> <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <u> <i> <b> <pre> <img> <abbr> <blockquote> <h1> <h2> <h3> <h4> <h5> <p> <div> <span> <sub> <sup>
  • Строки и параграфы переносятся автоматически.
  • Текстовые смайлы будут заменены на графические.

Подробнее о форматировании

CAPTCHA
Антиспам
1 + 1 =
Введите результат. Например, для 1+3, введите 4.
 
Новости

Открылась регистрация на мастер-классы по профессиональному Javascript, AJAX/COMET, jQuery в городах:

  • Ярославль (24-25 сентября)
  • Новосибирск (3-4 октября)
  • Казань (9-10 октября)
  • Минск (16-17 октября)
  • Днепропетровск (23-24 октября)
  • Одесса (30-31 октября)
  • Самара (13-14 ноября)

Более подробно - на странице мастер-классов.

Если вас интересует другой город - посмотрите здесь, выбрав "Другие города".

Текущий раздел
Поиск по сайту
Содержание

Учебник javascript

Основные элементы языка

Сундучок с инструментами

Интерфейсы

Все об AJAX

Оптимизация

Разное

Дерево всех статей

Статьи и мероприятия

Будьте в курсе наших последних новостей!

Последние обсуждения на форуме
Forum
Последние комментарии