Преимущества createElement по innerHTML?

На практике, каковы преимущества использования createElement по innerHTML? Я спрашиваю, потому что я убежден, что использование innerHTML более эффективно с точки зрения производительности и удобочитаемости/пригодности для обслуживания кода, но мои товарищи по команде обосновались на использовании createElement как подход кодирования. Я просто хочу понять, как createElement может быть более эффективным.

74
задан Gordon Gustafson 1 June 2010 в 00:41
поделиться

3 ответа

Использование createElement вместо модификации innerHTML дает несколько преимуществ (в отличие от того, чтобы просто выбросить то, что уже есть, и заменить его) помимо безопасности, как уже упоминал Пекка:

Сохраняет существующие ссылки на элементы DOM при добавлении элементов

Когда вы добавляете (или иным образом изменяете) innerHTML , все узлы DOM внутри этого элемента должны быть повторно проанализированы и воссозданы. Если вы сохранили какие-либо ссылки на узлы, они будут практически бесполезны, потому что больше не будут отображаться.

Сохраняет обработчики событий, прикрепленные к любым элементам DOM

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

В некоторых случаях может быть проще / быстрее

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

Кроме того, код обработки строк может быть более сложным (особенно, если вы хотите, чтобы он был безопасным).

Вот функция, которую я иногда использую, которая делает более удобным использование createElement .

function isArray(a) {
    return Object.prototype.toString.call(a) === "[object Array]";
}

function make(desc) {
    if (!isArray(desc)) {
        return make.call(this, Array.prototype.slice.call(arguments));
    }

    var name = desc[0];
    var attributes = desc[1];

    var el = document.createElement(name);

    var start = 1;
    if (typeof attributes === "object" && attributes !== null && !isArray(attributes)) {
        for (var attr in attributes) {
            el[attr] = attributes[attr];
        }
        start = 2;
    }

    for (var i = start; i < desc.length; i++) {
        if (isArray(desc[i])) {
            el.appendChild(make(desc[i]));
        }
        else {
            el.appendChild(document.createTextNode(desc[i]));
        }
    }

    return el;
}

Если вы назовете это так:

make(["p", "Here is a ", ["a", { href:"http://www.google.com/" }, "link"], "."]);

вы получите эквивалент этого HTML:

<p>Here is a <a href="http://www.google.com/">link</a>.</p>
71
ответ дан 24 November 2019 в 12:02
поделиться

Хотя innerHTML может быть быстрее, я не согласен с тем, что он лучше с точки зрения удобочитаемости или обслуживания. Сложить все в одну строку может быть короче, но более короткий код не всегда удобнее в сопровождении.

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

Результирующий элемент - это div с двумя внутренними промежутками, содержимое которых является динамическим. Одно из имен класса (воин) внутри первого промежутка также является динамическим.

<div>
    <span class="person warrior">John Doe</span>
    <span class="time">30th May, 2010</span>
</div>

Предположим, что следующие переменные уже определены:

var personClass = 'warrior';
var personName = 'John Doe';
var date = '30th May, 2010';

Используя только innerHTML и объединяя все в одну строку, мы получаем:

someElement.innerHTML = "<div><span class='person " + personClass + "'>" + personName + "</span><span class='time'>" + date + "</span></div>";

Вышеупомянутый беспорядок можно устранить с помощью замены строк, чтобы избежать открытия и закрытия строк каждый раз . Даже для простой замены текста я предпочитаю использовать replace вместо конкатенации строк.

Это простая функция, которая берет объект ключей и замещающих значений и заменяет их в строке. Предполагается, что ключи имеют префикс $ , чтобы обозначить, что это особое значение. Он не выполняет никаких экранирований и не обрабатывает крайние случаи, когда $ появляется в значении замены и т. Д.

function replaceAll(string, map) {
    for(key in map) {
        string = string.replace("$" + key, map[key]);
    }
    return string;
}

var string = '<div><span class="person $type">$name</span><span class="time">$date</span></div>';
var html = replaceAll(string, {
    type: personClass,
    name: personName,
    date: date
});
someElement.innerHTML = html;

Это можно улучшить, разделив атрибуты, текст и т. Д. При построении объекта, чтобы сделать объект более программным. контроль конструкции элемента. Например, с помощью MooTools мы можем передавать свойства объекта в виде карты. Это, безусловно, более удобно в обслуживании, и я бы сказал, что он более удобочитаемый. jQuery 1.4 использует аналогичный синтаксис для передачи карты для инициализации объектов DOM.

var div = new Element('div');

var person = new Element('span', {
    'class': 'person ' + personClass,
    'text': personName
});

var when =  new Element('span', {
    'class': 'time',
    'text': date
});

div.adopt([person, when]);

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

var div = document.createElement('div');

var person = document.createElement('span');
person.className = 'person ' + personClass;
person.appendChild(document.createTextNode(personName));

var when = document.createElement('span');
​when.className = 'date​​​​​​';
when.appendChild(document.createTextNode(date));

​div.appendChild(person);
div.appendChild(when);

Наиболее удобочитаемая версия, скорее всего, будет результатом использования какого-нибудь шаблона JavaScript .

<div id="personTemplate">
    <span class="person <%= type %>"><%= name %></span>
    <span class="time"><%= date %></span>
</div>

var div = $("#personTemplate").create({
    name: personName,
    type: personClass,
    date: date
});
15
ответ дан 24 November 2019 в 12:02
поделиться

Пользователь bobince очень и очень хорошо излагает ряд минусов в своей критике jQuery.

... Плюс, вы можете сделать div, сказав $(''+message+''), вместо того, чтобы возиться с document.createElement('div') и текстовыми узлами. Ура! Только... подождите. Вы не экранировали этот HTML и, вероятно, только что создали дыру в безопасности межсайтового скриптинга, только на этот раз на стороне клиента. И после того, как вы потратили столько времени на очистку PHP для использования htmlspecialchars на стороне сервера. Какой позор. А, ладно, никто ведь не заботится о правильности и безопасности, не так ли?

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

Что касается производительности: InnerHTML определенно будет медленнее, потому что его нужно разобрать и внутренне преобразовать в элементы DOM (возможно, используя метод createElement).

InnerHTML быстрее во всех браузерах, согласно quirksmode benchmark, предоставленному @Pointy.

Что касается читабельности и простоты использования, то в большинстве проектов я в любой день недели выбираю innerHTML вместо createElement. Но, как вы видите, есть много аргументов в пользу createElement.

12
ответ дан 24 November 2019 в 12:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: