Лучший способ создания больших статических элементов DOM в JavaScript?

У меня есть много элементов, которые один из моих виджетов 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" ) или $( "<div> " ) много раз, чтобы создавать элементы, добавлять их друг к другу там, где это необходимо, а затем присоединяться к документ:

function create() {
  return $("<div>").append($("<table>")......
}
$("body").append(create());

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

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

Ответ 1

Примечание. Если вы ненавидите чтение, просто проверьте сводку ниже для окончательного ответа

Возможно, вам действительно не нужно создавать их с помощью 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.


Обновление: test для себя, что самый быстрый метод 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 доступен, это лучший подход с точки зрения общей производительности браузера script.

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

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

Для получения дополнительной информации о документеFragment проверьте этот пост в блоге John Resig http://ejohn.org/blog/dom-documentfragments/

Ответ 2

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

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

Данные теста для сравнения: Создано 400 строк с 5 столбцами и добавлено в DOM. testData - это список объектов, которые вы получаете из backend в 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>

1st way: String Concatenation ( Оптимизированный способ с точки зрения производительности в браузерах)

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().

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

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

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+ millsec

3rd Way: использование 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

Ответ 3

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

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

Ответ 4

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

Ответ 5

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

EDIT: удаленный неправильный образец.

Или есть другой вариант, вы можете поместить 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()