Лучший способ создать большие статические элементы DOM в JavaScript? - PullRequest
31 голосов
/ 08 марта 2012

У меня есть много элементов, которые один из моих JS-виджетов должен часто создавать и добавлять в DOM.Они никогда не меняются.

Поэтому одним из вариантов будет сохранение самого HTML-кода в виде строки в JS и использование JQuery для создания элементов из строки, а затем добавление его в документ:

var elements = "<div><table><tr><td>1</td><td>2</td></tr></table></div>";
function create() {
  return $(elements);
}
$("body").append(create());

Другой вариант - написать функцию, которая будет использовать document.createElement ("div") или $ ("

") много раз для построения элементов, добавлять их друг к другу, где это необходимо, а затем добавлять к документу.:
function create() {
  return $("<div>").append($("<table>")......
}
$("body").append(create());

В первом случае у меня есть большая строка JS, которая на самом деле является HTML.Во втором случае у меня есть громоздкая часть JS, которая фактически представляет HTML.

Есть ли преимущества (недостатки) у одного или другого?Есть ли лучшее решение, о котором я не думаю?

Ответы [ 5 ]

29 голосов
/ 08 марта 2012

Примечание: если вы ненавидите чтение, просто посмотрите краткую сводку внизу для окончательного ответа

Может быть, вам не нужно создавать их с помощью jQuery.

Если структура этого HTML сложна (следовательно, использование метода document.createElement было бы излишним), я бы использовал атрибут innerHTML.

// somewhere in your code, preferably outside of global scope
var div = document.createElement('div')
div.id = 'mycustomdiv'
document.getElementsByTagName('body')[0].appendChild(div);
// assuming elements contains string of html with your elements
div.innerHTML = elements;

Таким образом, вы избегаете (предполагая снова) ненужных накладных расходов на создание и упаковку элементов в объекте jQuery.


Обновление: тест для себя, какой самый быстрый метод http://jsperf.com/creating-complex-elements. Этот тест подтверждает, что, когда вы пытаетесь сжать все до последней части производительности, возвращайтесь к ванильному JavaScript и классическим операциям DOM.


Обновление 2. Чтобы выяснить, почему метод innerHTML в Firefox 10 имеет такие плохие результаты в отношении передачи полной строки в jQuery.append, я взглянул на исходный код jQuery.

Как выясняется (в jQuery 1.7.1), они используют еще один способ создания элементов dom, используя document.createDocumentFragment (с некоторыми запасными вариантами, конечно, для браузеров, которые не имеют надлежащая поддержка).

DocumentFragments - это DOM-узлы. Они никогда не являются частью основного дерева DOM. Обычный вариант использования - создание фрагмента документа, добавление элементов к фрагменту документа и затем добавление фрагмента документа в дерево DOM. В дереве DOM фрагмент документа заменяется всеми его дочерними элементами.

Поскольку фрагмент документа находится в памяти и не является частью основного дерева DOM, добавление дочерних элементов к нему не вызывает перекомпоновку страницы .

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

Итак, подведем итог:

Я стою исправлено. Если вы ищете наилучшую производительность в разных браузерах при создании новых элементов DOM, сосредоточьтесь на фрагментах документов (используйте jQuery, если вы не хотите самостоятельно разбираться с различными угловыми случаями).

Чтобы узнать больше о documentFragment, прочтите этот пост в блоге Джона Резига http://ejohn.org/blog/dom-documentfragments/

26 голосов
/ 25 января 2015

Подробный анализ трех общих способов создания DOM в JS и лучший подход.

Я предоставлю 3 способа создания больших DOM, их плюсы и минусы, и, конечно же,самый оптимизированный способ создания больших DOM и почему.Суть в том, что при создании DOM в js нативные методы JS и DOM - ваши друзья, не используйте Jquery, если нет другого пути (что маловероятно).

Тестовые данные для сравнения: Создано 400 строк с 5 столбцами и добавлено в DOM.testData - это список объектов, которые вы получаете из бэкэнда в форме json для создания таблицы.

Прикрепленный моментальный снимок результата теста времени выполнения для разных браузеров enter image description here HTML

<div id="employeeListContainer1"></div>
<table id="employeeList2">
<thead>
    <tr>
        <th>First Name</th>
        <th>Last Name</th>
        <th>Title</th>
        <th>ID</th>
        <th>Department</th>
    </tr>
</thead>

1-й способ: конкатенация строк ( Наиболее оптимизированный способ с точки зрения производительности во всех браузерах)

var tableElementContainer1 = document.getElementById("employeeListContainer1"),
    temptableHolder  = '<table><thead><tr><th>First Name</th><th>Last Name</th><th>Title</th><th>ID</th><th>Department</th></tr></thead><tbody>';
        for(var i=0,len=testData.length; i<len; i++){
                temptableHolder  += '<tr><td>' + testData[i].firstName + '</td><td>' + testData[i].lastName + '</td><td>' + testData[i].title
                        + '</td><td>' + testData[i].id + '</td><td>'  + testData[i].department +  '</td></tr>';
            }
    temptableHolder += '</tbody></table>';
    tableElementContainer1.innerHTML  = temptableHolder ;

Плюсы: - Самое быстрое время выполнения в Firefox / Chrome / IE / Safari (от 3 до 5 миллисекунд в браузерах) .Измеряется с помощью API performance.now () и console.time ().

Минусы: - Когда количество столбцов больше и вам нужно установить много атрибутов, тогда работа со строками может стать немного труднее и менее сложной.tenable.

2-й способ: собственный Js document.createElement () (это 2-й лучший подход с точки зрения производительности во всех браузерах)

var tableBody = document.createElement('tbody'),
tableElement2 = document.getElementById("employeeList2"),  
    for(var i=0,len=testData.length; i<len; i++){
            tableRow = document.createElement("tr");
            for(var k in testData[i]){
                rowCell = document.createElement("td");
                rowCell.appendChild(document.createTextNode(testData[i][k]));
                tableRow.appendChild(rowCell);
            }
            tableBody.appendChild(tableRow);
        }
tableElement2.appendChild(tableBody);

Плюсы: - 2-е самое быстрое время выполнения в Firefox / Chrome / Safari (от 5 до 12 миллисекунд в браузерах) .Измеряется с помощью API performance.now () и console.time ().- Больше возможностей, чем у первого подхода

Минусы: - Время выполнения больше в браузерах IE, 90 + миллисекунда

3-й способ: использование Jqueryдля создания DOM (Мой совет - не используйте его)

var tableBody = $('<tbody></tbody>'),
  tableElement2 = document.getElementById("employeeList2"),  
        for(var i=0,len=testData.length; i<len; i++){
            tableRow = $("<tr></tr>");
            for(var k in testData[i]){
                rowCell = $("<td></td>");
                rowCell.append(testData[i][k]);
                tableRow.append(rowCell);
            }
            tableBody.append(tableRow);
        }
tableElement2.append(tableBody);

Плюсы: - Легко добавлять атрибуты / класс / стили к элементам, а также легко читать и использовать основные данные.

Минусы: - Наихудшее время выполнения во всех браузерах (от 220 мс до 330 мс) , самые медленные числа в IE

2 голосов
/ 08 марта 2012

Вы можете попробовать сделать AJAX-выборку статического HTML-блока вместо того, чтобы хранить его на самой странице.Это позволяет вам быть более гибким с тем, какой блок вы хотите вставить в будущем.

В качестве альтернативы (это просто случайная идея, которая не очень хорошо проработана), вы можете сохранить "структура "как данные JSON, а затем динамически анализировать их.Возможно что-то вроде {"div": {"div": {"span": "Text here"}}} для <div><div><span>Text here</span></div></div>.Я все еще пошел бы с AJAX все же.:)

1 голос
/ 08 марта 2012

Вы уже ответили себе.

РЕДАКТИРОВАТЬ: удален неправильный образец.

Или есть другой вариант, вы можете поместить HTML прямо в текущий html внутри скрытого div, как это:

<div id="hiddenContainer" style="display:none;">
    <div><table><tr><td>1</td><td>2</td></tr></table></div>
</div>

А потом в jquery вы можете прочитать это:

var elements = $("#hiddenContainer").html()
1 голос
/ 08 марта 2012

Если вы ищете производительность, я бы придерживался первой версии, потому что во второй каждый раз, когда вы вызываете $('<div>') или $('<table>'), вы создаете новый объект jQuery, а затем вызываете .append(), который также вызывает другой методВы делаете.
Я бы пошел с первым.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...