JavaScript

индекс
246,38

Javascript fluent html builder

Идея генерации html с помощью javascript меня не отпустила. Напомню eе суть с помощью jQuery
$("<div>", {"class":"something",id:10})

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

Теги, атрибуты и контент


//У нас есть переменная var h = Htmls которая содержит все теги.
h.div() == '<div></div>'
//У каждого тега есть методы для установки всех возможных атрибутов.
h.div().Class("some").Id(10) == '<div class="some" id="10"></div>'
//Так же имеется метод $(), для внутреннего контента тега.
h.div().$("some text") == '<div>some text</div>'


* This source code was highlighted with Source Code Highlighter.


В чем же преимущество перед стандартным подходом шаблонизаторов?


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

Рассмотрим задачу

var items = [1,2,3]
хотим получить
<ul>
 <li>1</li>
 <li>2</li>
 <li>3</li>
</ul>



Стандартный подход.

<% if(items.length) %>
<ul>
 <% for(var item in items){ %>
  <li><%= item %></li>
 <% } %>
</ul>
<% } %>



Не стандартный

function defaultUl(items){
  if(!items.length)
    return null
  return h.ul(items.map(function(i){
     return h.li(i);
  }));  
}

defaultUl(items);



Сравните что нам придется сделать при обоих подходах если понадобится другой список.

Нужно к li чего то добавить?
<ul>
 <li id="1">1</li>
 <li id="2">2</li>
 <li id="3">3</li>
</ul>


Не вопрос.
function defaultUl(items, trans){
  if(!items.length)
    return null
  return h.ul(
    items.map(function(i){
    return trans(h.li(i),i);
  }));  
}
defaultUl(items, function(tag, item){
  return tag.Id(item);
}



Еще один небольшой пример


var persons =
 [{id:1,name:"First", balance: 100},
 {id:2,name:"Second", balance: -200},
 {id:3,name:"Third", balance: 300}];



<table> 
  <tr><th>Name</th><th>Balance</th></tr>
  <tr id="1" class="green"><td>First</td><td>100</td></tr>
  <tr id="2" class="red"><td>Second</td><td>-200</td></tr>
  <tr id="3" class="green"><td>Third</td><td>300</td></tr>
</table>



var tr = function(tag, items){
 return h.tr(items.map(function(x){return tag(x);}));
};

h.Head = function(){
 var args = Array.prototype.slice.call(arguments);
 return tr(h.th, args);
};

h.Row = function(){
 var args = Array.prototype.slice.call(arguments);
 return tr(h.td, args);
};

with (Htmls) {

 var htmlPart = table(
  Head("Name", "Balance"),
  persons.map(function(p){
   return Row(p.name, p.balance).Id(p.id).Class(p.balance > 0 ? "green" : "red" );
  }));

}




Исходники


http://jshtmlbuilder.codeplex.com

Progg it
+4
29 августа 2010, 18:20
10

комментарии (12)

+15
shai_hulud #
имхо стало хуже читаться
–4
dotneter #
Думаю дело привычки, конечно xml в мозге поддерживается уже на аппаратном уровне, и с ним сложно конкурировать. Другой вопрос, нужно ли «читать» тот же ul когда там и так понятно что к чему.
+4
piumosso #
Чем хорош шаблон:
Имена классов и прочее в одном месте, а не раскиданы в конструкторах по коду.
Шаблон можно поменять / заменить, а код надо переписывать.
По коду сложно вообразить будущее форматирование / разметку.
Продолжать можно дальше)
0
bdiang #
Вашу библиотеку нельзя сравнивать с шаблонизаторами, которые призваны отделять логику от представления.

Что касается удобности и переиспользуемости — чем больше библиотека берет на себя, тем меньше гибкости остается. Атрибуты, теги — все это удобнее редактировать как раз в виде хтмл.

Ну и как то много телодвижений вы предлагаете на замену обычному циклу :)
–1
dotneter #
>Вашу библиотеку нельзя сравнивать с шаблонизаторами, которые призваны отделять логику от представления.
И в каком примере у меня не отделена логика от представления?
>Ну и как то много телодвижений вы предлагаете на замену обычному циклу :)
То есть совсем не видно что defaultUl практически один в один повторяет логику шаблона, которую к тому же можно повторно использовать?
0
Olegas #
JAML вам в помощь…

edspencer.github.com/jaml/
0
dotneter #
Я думаю
input.Type('submit').Value('Add to Cart')
немного читабельней
input({type: 'submit', value: 'Add to Cart'})
И судя по исходникам никакого подобия fluent интерфейса там нет, и реализация
function defaultUl(items, trans)
будет проблематичной.
0
Olegas #
Насчет читабельности — ИМХО на любителя. По мне JAML — читабельнее. Особенно когда eсть вложенность (как для статики, так и для заполнения шаблона данными). + у JAML явная реюзабельность шаблонов просто из коробки

fluent… а нужен ли он?

Проблем с defaultUl — нет никаких совсем. В добавок к этому при реализации ее с помощью Jaml получим реюзабельные шаблоны.

0
dotneter #
defaultUl это и есть реюзабельный шаблон, у меня для этого используются просто функции, у него же какая то система регистраций, плюсы которой я не осознал. Fluent нужен для того что бы в дальнейшем была возможность кастомизировать то что получается на выходе из шаблона.
например после того как я получить
var ul = defaultUl(items);
я могу легко добавить какие либо атрибуты.
ul.Class("something");
как вы это сделаете с помощью jaml?
Можете привести пример реализации шаблона для ul по типу defaultUl(items, trans) и с генерировать соответствующий хтмл из примера?
0
Olegas #
Вот табличка с персонами…

Jaml.register('table', function(personBook) {
table(
tr(th('Name'), th('Balance')),
Jaml.render('tableItem', personBook.persons);
);
});

Jaml.register('tableItem', function(person) {
tr(
{cls: person.balance<0?'red':'green', id: person.id },
td(person.name),
td(person.balance)
);
});

Jaml.render('table', personBook);

// personBook = { persons: [ Your array here ] };

Вот UL

Jaml.register('defaultUl', function(itemsContainer) { // Это вместо defaultUl
ul(Jaml.render(itemsContainer.desiredTamplateName, itemsConteiner.items); // Так можно заменить трансформацию.
});

Jaml.register('li-item', function(item) {
li({id: item.id }, item.name);
});

Jaml.render('defaultUl', { desiredTemplateName: 'li-item', items: [] );

Да, различие есть, нет вашей функции трансформации. Но это имхо не всегда плюс, получается очень размазанная по коду шаблонизация (один шаблон и куча разных функций трансформации). В случае JAML да, придется вместо каждой трансформации зарегистрировать свой шаблон элемента.
0
dotneter #
Очевидно что и с моей библиотекой, если человек для читабельности хочет дублировать разметку, то он может это делать, так что думаю мой вариант немного функциональнее.
И даже если вам нравится
input({type: 'submit', value: 'Add to Cart'})
Такой вариант тоже поддерживается.
0
Olegas #
С помощью JAML замену атрибутов после генерации сделать не удастся, это так.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.