Что лучше: добавлять новые элементы с помощью функций DOM или добавлять строки с тегами HTML? - PullRequest
21 голосов
/ 11 декабря 2011

Я видел несколько разных способов добавления элементов в DOM. Наиболее распространенными являются, например, либо

document.getElementById('foo').innerHTML ='<p>Here is a brand new paragraph!</p>';

или

newElement = document.createElement('p');
elementText = document.createTextNode('Here is a brand new parahraph!');
newElement.appendChild(elementText);
document.getElementById('foo').appendChild(newElement);

но я не уверен в преимуществах того или другого. Есть ли эмпирическое правило относительно того, когда одно должно быть сделано поверх другого, или одно из них просто неверно?

Ответы [ 6 ]

19 голосов
/ 11 декабря 2011

Некоторые заметки:

  • Использование innerHTML быстрее в IE, но медленнее в Chrome + Firefox. Вот один тест , показывающий это с постоянно меняющимся набором <div> с + <p> с; вот эталон , показывающий это для постоянной, простой <table>.

  • С другой стороны, методы DOM являются традиционным стандартом - innerHTML стандартизирован в HTML5 - и позволяют сохранять ссылки на вновь созданные элементы, чтобы вы могли изменить их позже.

  • Поскольку innerHTML быстр (достаточно), лаконичен и прост в использовании, заманчиво полагаться на него в любой ситуации. Но имейте в виду, что использование innerHTML отсоединяет все существующие узлы DOM от документа. Вот пример, который вы можете проверить на этой странице.

    Сначала давайте создадим функцию, которая позволит нам проверить, находится ли узел на странице:

    function contains(parent, descendant) {
        return Boolean(parent.compareDocumentPosition(descendant) & 16);
    }
    

    Возвращается true, если parent содержит descendant. Проверьте это так:

    var p = document.getElementById("portalLink")
    console.log(contains(document, p)); // true
    document.body.innerHTML += "<p>It's clobberin' time!</p>";
    console.log(contains(document, p)); // false
    p = document.getElementById("portalLink")
    console.log(contains(document, p)); // true
    

    Будет напечатано:

    true
    false
    true
    

    Может показаться, что использование innerHTML не могло повлиять на нашу ссылку на элемент portalLink, но это так. Это должно быть восстановлено снова для правильного использования.

5 голосов
/ 11 декабря 2011

Существует ряд отличий:

  1. innerHTML был стандартизирован только W3C для HTML 5; хотя в течение некоторого времени он был де-факто стандартом во всех популярных браузерах, технически в HTML 4 - это расширение поставщика, которое разработчики, придерживающиеся стандартов, никогда не будут застигнуты врасплох. С другой стороны, это намного удобнее и практически поддерживается всеми браузерами.
  2. innerHTML заменяет текущее содержимое элемента (оно не позволяет изменить его). Но опять же, вы получаете удобство, если вы не против этого ограничения.
  3. innerHTML было измерено , чтобы быть намного быстрее (по общему признанию, этот тест включает браузеры старых версий, которые сегодня не используются широко).
  4. innerHTML может представлять угрозу безопасности (XSS), если для него установлено значение, предоставленное пользователем, которое не было должным образом закодировано (например, el.innerHTML = '<script>...').

Исходя из вышеизложенного, кажется, что практический вывод может быть:

  • Если вы не возражаете против того факта, что innerHTML немного ограничивает (только полная замена поддерева DOM с корнем в целевом элементе), и вы не рискуете уязвимостью путем внедрения предоставленного пользователем контента, используйте это , В противном случае, идти с DOM.
1 голос
/ 22 марта 2019

Несмотря на то, что это старый поток, одна вещь, которая не упоминается, это то, что innerHTML может быть быстрее, следует позаботиться.Использование innerHTML отобразит каждого дочернего элемента измененного элемента, старого и нового.Таким образом, одно innerHTML назначение быстрее (немного), чем DOM create / append, но несколько innerHTML определенно будут медленнее.

Например:

for(let i=0; i < 10; i++)
   document.body.innerHTML+='<div>some text</div>';

будет почти в 5 раз медленнее, чем

let html = '';
for(let i=0; i < 10; i++)
   html += '<div>some text</div>';

document.body.innerHTML = html;

Поскольку назначение innerHTML позволяет браузеру создавать / добавлять элементы в исходное состояние,Второй метод приводит к тому, что 10 элементов создаются и добавляются в нативном режиме, в то время как первый метод приводит к созданию / добавлению 55 элементов (и 45 к уничтожению): 1 элемент создается при первой итерации цикла, 2 элемента создаются при второй итерации цикла (уничтожение оригинала), 3 элемента, созданных на третьей итерации цикла (предыдущие 2 уничтожаются), и так далее.

Если вы используете innerHTML для скорости, вы должны убедиться, что сначала создали всю строку html, прежде чем назначать innerHTML, например, при создании свежих контейнеров / элементов DOM.innerHTML, с другой стороны, теряет производительность при добавлении любого контейнера с существующими дочерними узлами, особенно с большим количеством дочерних узлов.

1 голос
/ 11 декабря 2011

Согласно этим данным теста , вы получите намного более быстрые результаты с innerHTML, чем при создании элементов DOM.Это особенно очевидно при использовании более старых версий IE.

0 голосов
/ 11 декабря 2011

Я всегда предпочитаю удобочитаемость, если разница не слишком велика. В разовом случае это, вероятно, будет незначительной разницей.

В таком случае, как этот, проще всего прочитать свойство innerHTML.

Но если вы выполняете много программной генерации контента на JavaScript, его проще и понятнее читать и понимать DOM.

Пример:

Сравнить innerHTML код:

http://jsfiddle.net/P8m3K/1/

// Takes input of a value between 1 and 26, inclusive,
// and converts it to the appropriate character
function alphaToChar(alpha)
{
    return String.fromCharCode('a'.charCodeAt() + alpha - 1);
}

var content = "<ul>";
for(i = 0; i < 10; ++i)
{
    content += "<li>";
    for(j = 1; j <= 26; ++j)
    {
        content += "<a href=\"" + alphaToChar(j) + ".html\">"
            + alphaToChar(j)
            + "</a>";
    }
    content += "</li>";
}
document.getElementById("foo").innerHTML = content;

К этому DOM-коду:

http://jsfiddle.net/q6GB8/1/

// Takes input of a value between 1 and 26, inclusive,
// and converts it to the appropriate character
function alphaToChar(alpha)
{
    return String.fromCharCode('a'.charCodeAt() + alpha - 1);
}

var list = document.createElement("ul");
for(i = 0; i < 10; ++i)
{
    var item = document.createElement("li");
    for(j = 1; j <= 26; ++j)
    {
        var link = document.createElement("a");
        link.setAttribute("href", alphaToChar(j) + ".html");
        link.innerText = alphaToChar(j);
        item.appendChild(link);
    }
    list.appendChild(item);
}
document.getElementById("foo").appendChild(list);

На этом уровне они начинают становиться довольно похожими по длине.

Но код DOM будет проще поддерживать, и вы с меньшей вероятностью допустите опечатку или ошибку, которую сложно диагностировать, например, опуская закрывающий тег. Либо ваши элементы будут в вашем документе, либо их нет.

  • С более сложными сценариями (такими как построение меню дерева) вы, вероятно, выйдете вперед с кодом DOM.
  • В сценариях, в которых вам нужно добавлять несколько типов контента вместе, чтобы создать документ с более разнородным контентом, он превращается в громадный данк. Вам не нужно обязательно вызывать код добавления своего ребенка перед вызовом кода добавления родителя.
  • В сценариях, где добавление, удаление или изменение существующего статического контента, DOM обычно побеждает.

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

0 голосов
/ 11 декабря 2011

Первый из них прост, проще для чтения, меньше кода и может быть быстрее.
Второй дает вам гораздо больший контроль над элементом, который вы создаете, то есть значительно упрощает изменение нового элемента с помощью JS (например,прикрепление событий, или, просто используйте его в своем коде).
Второй способ для «пуристов», которым нравится «чистый» код (не быстрый и не грязный).
Я говорю, используйте оба, посмотрите, что подходит вам лучшеи идти с этим.

...