Javascript.RU

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

Update: Более новый материал по этой теме находится по адресу https://learn.javascript.ru/template-lodash.
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 - 10: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)

Автор: bdiang, дата: 27 октября, 2010 - 10:51
#permalink

А вот так не скушает

<%=var;%>

Надо без точки с запятой в таких конструкциях.


Автор: Гость (не зарегистрирован), дата: 20 июня, 2011 - 10:40
#permalink

Я бы сделал даже так:

return function(o){
        try {
            fn(o);
        } catch(e) {
            e.message = "(Tpl-error) " + e.message;
            throw e;
        }
    }

Мы ведь говорим о RIA...


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

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

/* comment */

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


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

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


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

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


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

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

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


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

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


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

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


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

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

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


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

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


Автор: Гость (не зарегистрирован), дата: 25 мая, 2011 - 15:23
#permalink

мсье шутить изволит))


Автор: iyntx, дата: 31 января, 2012 - 09:12
#permalink

Зачем в серверном языке джаваскрипт-шаблоны ? :\


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

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


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

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


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

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


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

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


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

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

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

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


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

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


Автор: Shoorf (не зарегистрирован), дата: 16 июня, 2010 - 16: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 - 16:26
#permalink

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


Автор: Beck, дата: 29 ноября, 2010 - 00:07
#permalink

Вот вот, меня эта функция запутала, когда ковырял.
Собственно хотелось бы понять её смысл.


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

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


Автор: ixth, дата: 15 октября, 2010 - 14:50
#permalink

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

UPD. id шаблона должен подходить под регулярку \w+, иначе шаблонизатор принимает строку, переданную первым параметром в tmpl за шаблон, переданный текстом. Т.о. нельзя использовать дефисы в идентификаторах и такая запись не будет воспринята шаблонизатором как надо:

<script type="text/html" id="tpl-template">
...
var tpl = tmpl('tpl-template', obj);

Автор: rmaksim (не зарегистрирован), дата: 6 января, 2011 - 19:00
#permalink

для использования "-" в id-шках можно переделать

!/\W/ в !/[^\w-]/


Автор: Гость (не зарегистрирован), дата: 4 февраля, 2011 - 21:08
#permalink

Вот если кто-то любит жквери, а еще любит шаблоны держать отдельно от страниц, то тут показано, как можно загружать внешние шаблоны http://www.clearboth.ru/article/using-external-templates-with-jquery-tem...


Автор: Гость (не зарегистрирован), дата: 26 сентября, 2011 - 00:53
#permalink

поясните значение $1 при реплейсинге.


Автор: ViruSkin, дата: 18 октября, 2011 - 19:51
#permalink

Для шаблонизации я бы использовал связку js+XSLT


Автор: Гость (не зарегистрирован), дата: 28 сентября, 2012 - 18:00
#permalink

Самый лёгкий шаблонизатор (jQuery):

var template = '<div class="pop-up-overlay"></div>' +
                    '<div class="pop-up">' +
                    '  <div class="heading">{title}</div>' +
                    '  <div class="notify">{notify}</div>' +
                    '  <div class="content">{content}</div>' +
                    '</div>';

data = {
  title: 'Добавление товара в корзину', 
  notify: 'Прошло успешно!', 
  content: 'Товар "Погремушка" успешно добавлен в корзину покупок.'
}

function render(template, data) {
  var html = '';

  $.each(data, function(k, v){
    html = template.split('{' + k + '}').join(v);

    template = html;
  });

  return html;
}

$('body').prepend(render(template, data));

Автор: netkoatl (не зарегистрирован), дата: 22 октября, 2012 - 00:13
#permalink

У меня тупошаблонизатор похож на предложенный в комментариях, только синтаксис ещё проще: %varname подставляет значение.

А вот реализация - чуть сложнее; при инициализации он ищет все script[type="text/x-tpl"] и складывает в массив по id. Ну и вызов - Tpl.render(myTemplateId, dataObject).

Думал над раскатыванием шаблонов в кэш js-функций, как в основном посте; на таких тупых шаблонах особого выигрыша не даёт. А совать в шаблоны логику я не стану.


Автор: Гость (не зарегистрирован), дата: 17 декабря, 2015 - 11:59
#permalink

Замечательно!!! Спасибо.
Можно конечно использовать существующие библиотеки, но мне нравится этот вариант.
Можно использовать несколько шаблонов, разместив их в объекте.
Это наверное пригодилось бы при работе с содержимым балунов в гугл картах.

Я заменил открывающий и закрывающий тэги в шаблоне на $[[ и ]].

var obj_templ = {
	str_templ_1 : '\
<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>',
	str_templ_2 : '\
<div id="$[[id]]" >\
	<a href="/$[[from_user]]">\
		<img class="righted" src="$[[profile_image_url]]" style="width:90px;"/>\
		$[[from_user]]\
	</a>\
	$[[text]]\
</div>'
}
results_1.innerHTML = tmpl(obj_templ.str_templ_1)(dataObject);
results_2.innerHTML = tmpl(obj_templ.str_templ_2)(dataObject);

Автор: Гость (не зарегистрирован), дата: 21 июля, 2017 - 11:25
#permalink


Автор: Randy Hanson (не зарегистрирован), дата: 17 апреля, 2019 - 06:42
#permalink

It would be more wonderful if we can enjoy it right now.
google street view


Автор: Anna Shetty (не зарегистрирован), дата: 2 октября, 2019 - 09:32
#permalink

I appreciate the information you share, it helps me a lot
driving directions


Автор: shell shockers (не зарегистрирован), дата: 16 октября, 2019 - 10:38
#permalink

The article is very easy to understand, detailed and meticulous! I had a lot of harvest after watching this article from you! I find it interesting, your article gave me a new perspective! I have read many other articles on the same topic, but your article convinced me!


Автор: run 3 (не зарегистрирован), дата: 16 октября, 2019 - 10:40
#permalink

This is a great thing, I think everyone feels this information is very valuable, thank you
candy crush soda


Автор: malkovich, дата: 10 декабря, 2019 - 22:24
#permalink

good job gyus. THX.
router login


Автор: super smash flash 2 (не зарегистрирован), дата: 6 февраля, 2020 - 18:18
#permalink

This article is great. I like it very much. Thank you!


Автор: Гость (не зарегистрирован), дата: 6 февраля, 2020 - 18:19
#permalink

This article is great. I like it very much. Thank you!


Автор: Гость (не зарегистрирован), дата: 21 марта, 2020 - 06:08
#permalink

Your sharing is of great help to my work. I have learned a lot from this article of yours.
boxnovelicle of yours.


Автор: Гость (не зарегистрирован), дата: 4 апреля, 2020 - 00:04
#permalink

This article is nice. I like it. Thank you! PC Tricks


Автор: puka nola (не зарегистрирован), дата: 22 мая, 2020 - 04:59
#permalink

Your share is the great knowledge I have gathered, you are an important person I admire, thank you temple run 3


Автор: bob mikropol (не зарегистрирован), дата: 26 июня, 2020 - 16:56
#permalink

Found a lot of useful information, glad to join your community.
jiofi.local.html


Автор: Harry1 (не зарегистрирован), дата: 3 августа, 2020 - 09:46
#permalink

Thanks a lot for one’s intriguing write-up. It’s actually exceptional. Searching ahead for this sort of revisions. bettas for sale


Автор: cameliagobella (не зарегистрирован), дата: 19 августа, 2020 - 04:35
#permalink

Thanks for sharing this information. I really like your blog post very much. You have really shared a informative and interesting blog post with people Road Trip Planning


Автор: Isak Hansen (не зарегистрирован), дата: 9 сентября, 2020 - 18:16
#permalink

Wow the blog you give us is amazing, no wonder many people want to read this. https://celebrityinsider.org/


Автор: Kristian Kristensen (не зарегистрирован), дата: 9 сентября, 2020 - 18:18
#permalink

I will recomend this blog to all of my friends. Great article.
https://happygamer.com/


Автор: Aputsiaq Larsen (не зарегистрирован), дата: 9 сентября, 2020 - 18:24
#permalink

Thank you for this inspiring blog. I wait for more
https://ballstepded.com/


Автор: Mathias Filemonsen (не зарегистрирован), дата: 9 сентября, 2020 - 18:26
#permalink

I learned so much from this blog. Good inforamtion. https://fixoserror.com/


Автор: ГMathias Filemonsen (не зарегистрирован), дата: 9 сентября, 2020 - 18:28
#permalink

I wait for more.Great article.
https://premiereretail.com


Автор: Otto Josefsen (не зарегистрирован), дата: 9 сентября, 2020 - 18:31
#permalink

I stumbled across this blog.Great article. https://tecsprint.com


Автор: Arne Christensen (не зарегистрирован), дата: 9 сентября, 2020 - 18:32
#permalink

Thank you for this amazing blog. Congratulations.
https://howtolose10poundsinaweek.com


Автор: Гость (не зарегистрирован), дата: 9 сентября, 2020 - 18:33
#permalink

The things i see here are very informative. Keep going. https://bargainistafashionista.com


Автор: Гость (не зарегистрирован), дата: 9 сентября, 2020 - 18:35
#permalink

I can say that is one of the best articles out on the internet. https://bankncard.com


Автор: Гость (не зарегистрирован), дата: 9 сентября, 2020 - 18:37
#permalink

I readed all the article. So informative https://vhan.net


Автор: Гость (не зарегистрирован), дата: 10 сентября, 2020 - 16:21
#permalink

This is one of the best sites i have found on the internet until now. Nice article keep going.
https://millikenconstructioninc.com/


Автор: Гость (не зарегистрирован), дата: 11 сентября, 2020 - 16:15
#permalink

Thanks for the information, very clear and simple. I will try to use it.Love the way you write. Working my way through your article links
https://vvhen.to/


Автор: Гость (не зарегистрирован), дата: 15 сентября, 2020 - 12:09
#permalink

This is one of the best articles i found on the blogs around the internet. I am really interested in seeing more of this. Keep going with the great work!
https://gzgjskpzz1m.ga


Автор: Гость (не зарегистрирован), дата: 19 сентября, 2020 - 10:56
#permalink

First of all ,you have picked a very unique theme . I think i might design something similar for a future project that i want to build .
On top of that ,i in truth enjoy most of your content pieces and your different point of view.
Thank you https://seoconsultants24.blogspot.com/


Автор: Гость (не зарегистрирован), дата: 19 сентября, 2020 - 11:34
#permalink

Nice information, many thanks to the author. It is incomprehensible to me now, but in general, the usefulness and significance is overwhelming.https://seokarma24.blogspot.com/


Автор: Гость (не зарегистрирован), дата: 19 сентября, 2020 - 15:20
#permalink

I have reviewed the article many times and I find it very impressive. The information is extremely useful especially the last part I care about that information very much. I have been looking for this certain information for a long time.
https://packseo.blogspot.com/


Автор: Гость (не зарегистрирован), дата: 23 сентября, 2020 - 16:59
#permalink

I’m gone to tell my little brother, that he should
also pay a quick visit this blog on regular basis to take updated from hottest information.
https://connectorseo.blogspot.com/


Автор: Гость (не зарегистрирован), дата: 23 сентября, 2020 - 17:13
#permalink

Fantastic blog! Do you have any helpful hints for aspiring writers?
I’m hoping to start my own site soon but I’m a little lost on everything.
https://sweetseo24h.blogspot.com/


Автор: Гость (не зарегистрирован), дата: 23 сентября, 2020 - 18:16
#permalink

I am hoping the same best effort from you in the future as well. In fact your creative writing skills has inspired me.
https://fancyseo24h.blogspot.com/


Автор: Гость (не зарегистрирован), дата: 29 сентября, 2020 - 16:26
#permalink

You have made some really good points there. I looked on the web to find out
more about the issue and found most individuals will go along with your views on this website
https://phoenixseogeek.com/


Автор: Гость (не зарегистрирован), дата: 1 октября, 2020 - 21:56
#permalink

Nice information, many thanks to the author. It is incomprehensible to me now, but in general, the usefulness and significance is overwhelming.
https://zgjskpzz1m.ga/


Автор: 먹튀검증 (не зарегистрирован), дата: 14 ноября, 2020 - 17:17
#permalink

Thanks for your information, it was really very helpfull 먹튀검증


Автор: 대출 (не зарегистрирован), дата: 14 ноября, 2020 - 17:17
#permalink

Wow what a Great Information about World Day its very nice informative post. thanks for the post 대출


Автор: <a href="https://twiddeo.com" target="_blank" class="postlin (не зарегистрирован), дата: 25 ноября, 2020 - 08:06
#permalink

토토사이트 Hello! Nice to meet you. 먹튀검증First of all,안전놀이터 thank you very much for 토토사이트providing us with this variety of information. 꽁머니I think it's information that can be used in many ways. I can't imagine how much effort you've made to write this. Thank you for your hard work. I would appreciate it if you would continue to provide us with such information. In addition, COVID-19 is becoming a problem all over the world these days. I hope there's no harm to you and your family. 먹튀가디언 Thank youhttps://twiddeo.com/And, 먹튀검증토토사이트 Already 2020 is nearing the end. 메이저토토사이트 There were so many incidents this year. 사설토토 I am still feeling a lot of inconvenience and birds due to the special virus. 먹튀사이트조회It's already getting 토토사이트 a lot colder, 안전놀이터 so make sure to 먹튀검증 pack warm clothes. 먹튀요기요 Please spend the rest of https://mtygy.com/ your life happy. 메이저놀이터 Then, have a nice day!놀이터토토 https://twiddeo.com/


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

Приветствуются комментарии:
  • Полезные.
  • Дополняющие прочитанное.
  • Вопросы по прочитанному. Именно по прочитанному, чтобы ответ на него помог другим разобраться в предмете статьи. Другие вопросы могут быть удалены.
    Для остальных вопросов и обсуждений есть форум.
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
Антиспам
2 + 8 =
Введите результат. Например, для 1+3, введите 4.
 
Текущий раздел
Поиск по сайту
Содержание

Учебник javascript

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

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

Интерфейсы

Все об AJAX

Оптимизация

Разное

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

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