Задача: в JS на основе имеющихся данных сгенерить блок (кусок хтмл), заполнить его этими данными и вставить в DOM.
Например, нам нужно создать простой блок с превьюшкой и подписью. Для него мы каким-то образом получили вот такие данные:
var data = {
url: '/test/',
thumb_src: 'test.gif',
thumb_width: 60,
thumb_height: 30,
caption: 'Трам-парам!'
};
В итоге для этих данных хотим получить вот такой хтмл:
<div class="preview"><p class="image"><a href="/test/"><img src="test.gif" width="60" height="30"/></a></p><p class="caption">Трам-парам!</p></div>
Встают вопросы: в каком виде хранить шаблон и как впердолить в этот шаблон наши данные?
Вручную создавать элементы (createElement) и аппендить их (appendChild) довольно муторно. Получается громоздко и шаблон размазывается тонким слоем по JS-коду.
Часто делают конкатенацию кусочков шаблона вперемешку с данными:
var result = '<div class="preview"><p class="image"><a href="' + data.url + '"><img src="' + data.thumb_src + '" width="' + data.thumb_width + '" height="' + data.thumb_height + '"/></a></p><p class="caption">' + data.caption + '</p></div>';
Тоже не ахти — постоянно путаешься в этом нагромождении одинарных и двойных кавычек, к тому же хочется все-таки иметь шаблон в чистом виде.
Я использую способ, который подсмотрел в лекциях Дугласа Крокфорда. Добавляем в прототипы объекта String
метод supplant
, который в строке ищет выражения заключенные в фигурные скобки {}. Каждое найденное выражение используется как ключ к переданному объекту, и, если по этому ключу лежит строковое или числовое значение, то выражение в фигурных скобках заменяется этим значением.
/**
* supplant() does variable substitution on the string. It scans
* through the string looking for expressions enclosed in {} braces.
* If an expression is found, use it as a key on the object,
* and if the key has a string value or number value, it is
* substituted for the bracket expression and it repeats.
*/
String.prototype.supplant = function(o) {
return this.replace(/{([^{}]*)}/g,
function(a, b) {
var r = o[b];
return typeof r === 'string' || typeof r === 'number' ? r : a;
}
);
};
Теперь мы можем сделать так:
var template = '<div class="preview"><p class="image"><a href="{url}"><img src="{thumb_src}" width="{thumb_width}" height="{thumb_height}"/></a></p><p class="caption">{caption}</p></div>';
var result = template.supplant(data);
Еще один пример (подстановка данных в сообщение пользователю):
var template = 'Take train {number} from {from} to {to}.';
var data = {
from: 'Madrid',
to: 'Barcelona',
number: '78A'
};
var result = template.supplant(data);
13 комментариев:
огромное Вам спасибо!
Сам часто работаю с JSON строками, и призодится делать обычным сложением строк
Ваш метод куда более красив
ЭТО ОЧЕНЬ КРУТО!!! Думаю было бы здорово встроить это в jQuery по умолчанию)
kulakowka, ничто не мешает вам оформить это как плагин к jQuery!
Сергей, да, это довольно удобно для распечатывания JSON данных :)
Но для других применений пока не додумался :(
Заходите к нам ;) http://vl.vg/
Заслуживает внимания способ, предложенный Джоном Ресигом: компилирование шаблона в функцию.
Спасибо. Как раз думал как бы мне прототипчик типа подобного добавить в свой dotPlant CMS
Привет ещё раз!)
Вышел codeEvaluator 0.0.3rc1 Прошу протестировать до выхода релиза по этой ссылочки http://vl.vg/24.01.2010/method-introduced-by-setting/#ce-0-0-3rc1
Спасибо! Отличный способ!
В Dojo Toolkit в пакете dojo.string
есть функция dojo.string.substitute
Пример использования:
dojo.string.substitute(
"File '${name}' is not found in directory '${info.dir}'.",
{ name: "foo.html", info: { dir: "/temp" } }
);
таже мысль но на пару дней раньше
http://mabp.kiev.ua/2010/01/16/javascript-template-engine/
Вообще советую полазить по коду разных джс-фреймворков. Насколько я помню, этот прием несколько лет назад в коде экст.джс подсмотрел.
Для джквери использую http://plugins.jquery.com/project/jquerytemplate
У прототайпа сразу есть класс Template.
Еще замечу, что самая быстрая конкатенация делается с помощью массива, а рендер с помощью иннерШТМЛ:
var template = new Template('option value="#{id}">#{name} option');
var options = []
for(var i=0;i<cities.length;i++)
{
var city = cities[i];
options.push(template.evaluate(city));
}
this.cbCity.innerHTML = options.join("");
Шаблонизатор на javascript, прикольно :)
Советую глянуть на шаблонизатор из underscore.js
http://documentcloud.github.com/underscore/#template
По сути - создаётся спрятанный HTML внутри script-тэга, который заполняется передаваемыми туда данными. Есть условные операторы, циклов не видел.
Отправить комментарий