JavaScript: создание DOM фрагментов

    Если приходилось когда-нибудь писать JavaScript и приходилось в JavaScript’е писать что-то вроде:
    var p = document.createElement( «p» );
    p.appendChild( document.createTextNode( «Настоящий рыба фиш.» ) );
    var div = document.createElement( «div» );
    div.setAttribute( 'id', 'new' );
    div.appendChild( p );

    то это может быть вам полезно.

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

    Предлагаю простой инструмент решения задачи — функцию create() (исходник ниже). Например, создаём абзац текста:
    var el = create( «p», { }, «Farewell, Love!» );

    Или div с параграфом и ссылкой внутри него:
    var div = create( «div», { id: «new», style: «background:#fff» },
    create( «p», { align: 'center' },
    «вступление: »,
    create( 'a', { href: «ua.fishki.net/picso/kotdavinchi.jpg» },
    «картинка» ),
    ": конец" )
    );

    Или вот, делаем таблицу:
    var holder = document.getElementById( «holder2» );
    var table;
    var td;
    holder.appendChild(
    table =
    create( «table», {id: 'ugly', cols:3},
    create( «tbody», {},
    create( «tr», {},
    create( «td», { width: '10%' },
    «hello» ),
    td =
    create( «td», { style: 'background: #fcc' },
    «there» ),
    create( «td», { Class: 'special2' }, «everywhere» )
    )
    )
    )
    );

    Обратите внимание:


    1. IE требует tbody элемент, иначе отказывается показывать таблицу.
    2. Аттрибут class с чем-то конфликтует, поэтому приходится писать его как Class. Кажется, на результат это влияния не оказывает.
    3. table = и tr = в примере позволяют сохранить созданные вложенные объекты для дальнейшей работы с ними.
    4. Этот код работает и в IE, и в Mozilla, и в Opera.

    Сама функция


    function create( name, attributes ) {
    var el = document.createElement( name );
    if ( typeof attributes == 'object' ) {
    for ( var i in attributes ) {
    el.setAttribute( i, attributes[i] );

    if ( i.toLowerCase() == 'class' ) {
    el.className = attributes[i]; // for IE compatibility

    } else if ( i.toLowerCase() == 'style' ) {
    el.style.cssText = attributes[i]; // for IE compatibility
    }
    }
    }
    for ( var i = 2;i < arguments.length; i++ ) {
    var val = arguments[i];
    if ( typeof val == 'string' ) { val = document.createTextNode( val ) };
    el.appendChild( val );
    }
    return el;
    }

    За идею следует благодарить Ивана Курманова,
    Оригинальная статья с работающими примерами: ahinea.com/2006/04/14/javascript-dom-create

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

    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

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

    • НЛО прилетело и опубликовало эту надпись здесь
        +1
        Спасибо, Вы по ходу первый читатель, т. к. кабракатонул сразу же через 5 сек после добавления статьи :)
          +4
          это хаброкатохабробот
        +2
        Красиво, конешна, но насколько оно применимо в реальной жизни в свете вот этого ?
          0
          ИМХО: В реальной жизни очень даже применимо, InnerHTML конечно же быстрее работает чем W3C DOM, ничего тут не поделаешь.

          Я лично решал довольно таки простые задачи и кода генерировать приходилось немного, с проблемами производительности не сталкивался
            0
            Я имею ввиду с проблемами производительности при генерации документа средствами javascript не сталкивался :)
              0
              С ними сталкивались посетители сайтов. Попробуйте как-нибудь ваше творение на машинке с 500-700MHz P!!!. Такие машинки ещё в строю!
                +3
                а это уже их проблемы. Наверное глупо говорить "у меня че-та тама тормозит", когда сидишь на железе из прошлого века.
                  +1
                  Я как-то работал в крупной фирме (ок. 1000 сотрудников, в 10-ке по России) в сфере торговле радиоэлектронными компонентами. Так вот. Регулярные заказы на несколько десятков тысяч евро делал дяденька на 200 MMX(!!!). Ну не у всех заводов еще комп. парк обновлен:)

                  Кроме того, не стоит забывать про мобильные устройства, которые еще проигрывают в производительности десктопным компам.
                    +1
                    У дяденьки на 200MMX небось какой-нибудь IE3, в котором вообще ничего не работает.
                    На средне-устаревшей тачке (от 1ГГц) разница между innerHTML/DOM будет заметна только при частой перерисовке очень больших объемов.
              0
              innerHTML работает быстрее чем DOM. Впервые об этом слышу.
                0
                Читай ссылку выше, я тоже об этом сегодня узнал :)
                p.s.: Опубликовал статью — получил полезный скилл про innerHTML
                  0
                  Почитал. С домом привычнее, и если грамотно писать - приятнее.
              0
              Из этого следует что лучше делать все что можно через InnerHTML? Или у него есть свои недостатки перед DOM методами?
                +3
                innerHTML не существует в XHTML.
                  +1
                  У него читабельность хромает. Но он быстрее. В нормальных браузерах (Firefox/Opera/Safari) разница не так велика и может компенсироваться тем, что потом придётся в отдельный проход находить подэлементы (типа переменной td в последнем примере), но в MS IE разница просто катастрофична: в 30 и более раз! Причём самое ужасное - MS IE 6 и MS IE 7 в этом отношении хуже, чем MS IE 5, так что облегчения в будущем не предвидится...
                  • НЛО прилетело и опубликовало эту надпись здесь
                      +1
                      При создании элементов средствами innerHTML - остаётся неизвестным указатель на созданный объект. Для этого придётся прибегать к поиску его в документе.
                      А средствами DOM мы имеем указатель сразу после создания элемента — var table=document.createElement('table');
                        +1
                        К плюсам innerHTML относится не только скорость, но и простота для разработчика. innerHTML одинаково поддерживают все браузеры. С DOM`ом же у IE (особенно 6ой версии) есть проблемы (например, вставка input type="radio"). Подробнее с ошибками IE можно ознакомиться на Channel9 wiki.

                        Я вижу только 2 минуса innerHTML:
                        1. он отсутствует в стандартах. Для меня полностью компенсируется одинаковой поддержкой во всех известных мне графических интернет-браузерах (IE,FF,Opera,Safari,Konqueror).
                        2. нельзя сразу получить ссылку на созданный элемент. На практике мне несколько раз надо было это сделать. Брал либо через document.getElementById, либо через DOM детей от элемента в который вставляли.

                        Непрактичность DOM показывает кол-во функций, которые по сути стремятся приблизиться к innerHTML, но используя DOM. Тут, как мне кажется, надо менять стандарт, а не заниматься самоистязанием. Тем более что все основные браузеры уже поддерживают эту функциональность.

                        Для себя при необходимости вставки нетривиальных DOM-фрагментов я использую innerHTML и текстовые шаблоны, где значения параметрам вида %NAME% подставляется простой заменой подстроки в строке.
                          0
                          innerHTML глючит в ослике, очень часто нельзя потом найти по id новоиспеченный домнод, вставленный через innerHTML
                        0
                        да, сильно. Особенно радует IE6 - разница почти в 20(!) раз.
                        Выходит не зря я пользуюсь innerHTML всюду где можно
                        0
                        Только, ради бога, не параграф, а абзац. Спасибо.
                          0
                          Спасибо, исправил :)
                          +7
                          С помощью jQuery, например, подобное очень просто реализуется. Кроме того в библиотеке море других полезностей и удобств, ради которых не жалко подключить 20-килобайт кода, а не писать кучу своих функций, реализующих то, что уже есть реализованное.
                            0
                            только написать хотел :)
                              +1
                              речь то шла не о библиотеке, а о реализации DOM helper-а и только оного, иначе можно приводить до сотни разных библиотек, включающих в себя работу с DOM. Наверное есть реализации, в которых работа с DOM происходит удобнее и проще, чем в jQuery.
                                0
                                Мне кажеться проще чем в jQuery уже некуда :)
                                  0
                                  может только кажется? Вроде встречал на просторах Ajaxian-а и поэлегантнее варианты.
                                    0
                                    Но поэлегантнее, не всегда проще или если угодно понятней.
                                      0
                                      нет смысла продолжать трэд, своим комментарием я хотел сказать, что кроме jQuery существует миллион с хвостиком разных библиотек и приблуд «все в одном», но когда нужно только ОДНО (в данном случае вставка в DOM дерево) нет смысла упоминать эти комбайны.
                                0
                                А вот и не понятно, как с помощью jQuery можно реализовать те примеры, которые приводит автор. Не просто через вставку HTML, типа:

                                $('<div id="new" style="background:#fff""><p align="center">вступление : <a href="http://ua.fishki.net/picso/kotdavinchi.jpg">картинка</a> : конец</p></div>').appendTo('#destination');

                                - потому что так, семантика смешивается с контентом. А чтобы именно через создание DOM модели, как это сделано у автора?
                                  0
                                  $( "<div>" );

                                  А теперь можно к нему добавлять аттрибуты, вставить контент и т.д.
                                    0
                                    Верно, после твоего ответа решил поиграться и написать все примеры автора через jQuery, чтобы было с чем сравнивать, итак, что у меня получилось:

                                    Например, создаём абзац текста:


                                    $('<p>').append('Farewell, Love!').appendTo('#destination');


                                    Или div с параграфом и ссылкой внутри него:


                                    $('<div>')
                                        .attr('id','new')
                                        .css('background','#fff')
                                        .append(
                                            $('<p>')
                                                .attr('align','center')
                                                .append('вступление :')
                                                .append(
                                                    $('<a>')
                                                        .attr('href','http://ua.fishki.net/picso/kotdavinchi.jpg')
                                                        .append('картинка')
                                                )
                                                .append(': конец')
                                        ).appendTo('#destination');


                                    Или вот, делаем таблицу:


                                    $('<table>').attr({id:'ugly',cols:3}).append(
                                            $('<tbody>')
                                                .append(
                                                    $('<tr>')
                                                        .append(
                                                            $('<td>').attr('width','10%').append('hello')
                                                        )
                                                        .append(
                                                            $('<td>').addClass('special2').append('everywhere')
                                                        )
                                                )
                                        ).appendTo('#destination');


                                    На мой взгляд ,смотрится не хуже, а для каких-то моментов наверняка и более надежно, с точки зрения кросс-браузерности.
                                      0
                                      О том и речь ,)
                                0
                                На сколько я понимаю, то при вставке кода через innerHTML мы не сможем потом даже сделать элементарный getelementbyid... или я чтото путаю... так что считаю вышеприведенный метод вполне применимым на практике
                                  0
                                  getelementbyid вполне работает при использовании innerHTML
                                    0
                                    ну значит я что то напуал сказав это...
                                  0
                                  Хм. Такие вещи уже давно есть во многих фреймворках, в mootools например.
                                  Так что не надо благодарить за идею Ивана Курманова, вот.
                                    0
                                    Он эту функцию написал
                                    0
                                    Форматирование кода полезная штука, чесслово.
                                      0
                                      Согласен.
                                      0
                                      совсем не ново.
                                      –1
                                      Шото я не вьехал что вы тут обсуждаете. Производительность каждый может сам проверить что работает быстрее у себя на компах каждый. Сам пост - тоже не врубился что он за америку открывает.

                                      .class - атрибут не работает наверное не почему-то, а потому что его нужно называть .className
                                        0
                                        А почему, скажите мне пожалуйста, мой пост обязательно должен открывать Америку?
                                        Я просто написал о вещи, которой сам пользуюсь, это вовсе не тайна что статья с этой функцией написана еще в 2006 году, и вполне возможно, что кто-то сочтет приемлимым и даже очень удобным использование такой функции. Почему бы нет?
                                        Мне показалось, что это интересная для Хабра статья, именно такая, какими они и должны здесь быть. О полезной, не банальной и не широко известной вещи, вроде-бы не боян, а если здесь сидят одни гуру джаваскрипта, то зачем вообще что-то читать?
                                        Пишите лучшие статьи, я с удовольствием почитаю! :)
                                          –1
                                          Да вообще-то я собирался написать очень интересный и поучительный пост, но какой-то Карма-контроль меняне пускает ничего писать
                                            0
                                            ЛОЛ :))))
                                            Надеюсь, в ближайшее время пустит
                                        0
                                        По названию статьи подумал, что тут будет обсуждаться document.createDocumentFragment - полезная штука, подглючивающая в ФФ.
                                          0
                                          бррр... велосипед...
                                            0
                                            prototype:
                                            The old way
                                            var a = document.createElement('a');
                                            a.setAttribute('class', 'foo');
                                            a.setAttribute('href', '/foo.html');
                                            a.appendChild(document.createTextNode("Next page"));

                                            The new way
                                            var a = new Element('a', { 'class': 'foo', href: '/foo.html' }).update("Next page");
                                              +1
                                              Спасибо за статью! Несколько замечаний:

                                              setAttribute с некоторыми атрибутами глючит в IE, поэтому следует вместо этого использовать просто el[i] = attributes[i].

                                              class не работает, потому что это в JavaScript зарезервированное слово. Вместо него можно писать 'class' (в кавычках) или className.

                                              И, кстати, за идею стоит благодарить Томаса Фухса, создателя библиотеки Script.aculo.us (в последствии этот функционал перекочивал в сам Prototype).

                                              И еще. Хорошо бы окружить куски кода тагом pre, чтобы идентацию сохранить, а то так малочитабельно.
                                                0
                                                Спасибо, совсем забыл про pre
                                                  0
                                                  Так почему не поправишь? :)
                                                  0
                                                  насколько я помню, это только id (не знаю уж причины к сожалению), class (так как используется для других целей, а для указания класса нужен className) и style (некроссбраузерно и по моему удобнее делать через хеш стилей)
                                                    0
                                                    Нет, id нормально работает. Не работает еще for по понятной причине - нужно htmlFor.

                                                    А вот style действительно приходится отдельно в цикле разбирать внутри той функции, передавая его как хеш.
                                                      0
                                                      про id да, наврал
                                                      а вот for тоже хорошо работает в setAttribute
                                                      проблема в том, что если не заключать for в кавычки, его нельзя использовать как ключ хэша, больше этот атрибут мне проблем не доставлял )
                                                        0
                                                        setAttribute вроде и с некоторыми другими словами глючит в IE, надёжнее всё-таки напрямую по-моему. :)
                                                          0
                                                          ага например colspan не срабатывает через setAttribute
                                                  0
                                                  всегда пользовался и буду пользоватся innerHTML. Лично мне гораздо удобнее читать код с innerHTML, чем с созданием элементов способом автора.
                                                    +1
                                                    с хорошими отступами подобное создание дерева информативнее, удобнее и правильнее =)
                                                    0
                                                    Статья полезная, спасибо, хотя я согласен с мнением читателей: это уже организовано в JS библиотеках, как JQuery или mootools.

                                                    Но не в этом суть!
                                                    Я бы хотел напомнить что есть раздел JavaScript и мне кажется, что логичнее было бы разместить эту статью туда... Но хозяин - барин :)

                                                    А так, хаброчеловеки, обращайте внимание на коллективные блоги, а то есть некоторая неразбериха между блогами "Ajax", "Web-разработка" и "JavaScript" (дублирующиеся темы новостей Ext тому пример).

                                                    Спасибо!
                                                      +1
                                                      Подобную вещь сделал давно и активно пользуюсь

                                                      Украду:
                                                      - переменное кол-во аргументов; я "детей" указывал в массиве третьим параметром

                                                      Вам посоветую:
                                                      - стили тоже может быть стоит в массив загонять? я так делаю - удобнее и практичнее
                                                      - class, for (label for="..."), как уже выше сказали, надо заключать в кавычки/апострофы - это правильнее, к тому же это позволит убрать toLowerCase =)
                                                      - насколько помню (сейчас лениво проверять) id надо тоже отдельно обрабатывать - не через setAttribute, а прямым назначением
                                                      - у меня ф-ия называется node, имхо более соответствует
                                                        0
                                                        про id наврал, дико извиняюсь, setAttribute хорошо с ним дружит
                                                      • НЛО прилетело и опубликовало эту надпись здесь

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

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