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
    Поделиться публикацией

    Похожие публикации

    Комментарии 12

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

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

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

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

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

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

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

                      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
                        Очевидно что и с моей библиотекой, если человек для читабельности хочет дублировать разметку, то он может это делать, так что думаю мой вариант немного функциональнее.
                        И даже если вам нравится
                        input({type: 'submit', value: 'Add to Cart'})
                        Такой вариант тоже поддерживается.
                        0
                        С помощью JAML замену атрибутов после генерации сделать не удастся, это так.

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

                Самое читаемое