首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >与innerHTML相比,createElement的优势是什么?

与innerHTML相比,createElement的优势是什么?
EN

Stack Overflow用户
提问于 2010-06-01 08:30:13
回答 4查看 37.8K关注 0票数 82

在实践中,与innerHTML相比,使用createElement有哪些优势?我之所以问这个问题,是因为我确信使用innerHTML在性能和代码可读性/可维护性方面更有效率,但我的队友已经决定使用createElement作为编码方法。我只是想了解createElement如何才能更高效。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2010-06-01 10:38:36

除了安全性之外,使用createElement而不是修改innerHTML有几个优点(而不是仅仅扔掉已经存在的东西并替换它),就像Pekka已经提到的那样:

在追加元素时保留对DOM元素的现有引用

当您附加(或修改) innerHTML时,必须重新解析和重新创建该元素中的所有DOM节点。如果您保存了对节点的任何引用,它们基本上都是无用的,因为它们不再出现。

保留附加到任何DOM元素的事件处理程序

这实际上只是最后一个的特例(尽管很常见)。设置innerHTML不会自动将事件处理程序重新附加到它创建的新元素,因此您必须自己跟踪它们并手动添加它们。在某些情况下,事件委托可以消除此问题。

在某些情况下可以更简单/更快

如果您正在做大量的添加,您肯定不想一直重置innerHTML,因为尽管简单的更改会更快,但重复地重新解析和创建元素会更慢。解决这个问题的方法是在字符串中构建一个超文本标记语言,并在完成后设置一次innerHTML。根据情况的不同,字符串操作可能比仅仅创建元素并附加元素慢。

此外,字符串操作代码可能更复杂(特别是如果您希望它是安全的)。

下面是我有时使用的一个函数,它使使用createElement变得更加方便。

代码语言:javascript
复制
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;
}

如果你这样称呼它:

代码语言:javascript
复制
make(["p", "Here is a ", ["a", { href:"http://www.google.com/" }, "link"], "."]);

您将获得与此HTML等效的内容:

代码语言:javascript
复制
<p>Here is a <a href="http://www.google.com/">link</a>.</p>
票数 83
EN

Stack Overflow用户

发布于 2010-06-01 10:57:12

虽然innerHTML可能更快,但我不同意它在可读性或维护性方面更好。将所有内容放在一个字符串中可能会更短,但更短的代码并不一定更易于维护。

当需要创建动态DOM元素时,字符串连接不能伸缩,因为加号和引号的开头和结尾很难跟踪。考虑以下示例:

结果元素是一个具有两个内部跨度的div,其内容是动态的。第一个跨度中的一个类名(warrior)也是动态的。

代码语言:javascript
复制
<div>
    <span class="person warrior">John Doe</span>
    <span class="time">30th May, 2010</span>
</div>

假设已经定义了以下变量:

代码语言:javascript
复制
var personClass = 'warrior';
var personName = 'John Doe';
var date = '30th May, 2010';

只使用innerHTML并将所有内容混合到一个字符串中,我们得到:

代码语言:javascript
复制
someElement.innerHTML = "<div><span class='person " + personClass + "'>" + personName + "</span><span class='time'>" + date + "</span></div>";

上面的混乱可以通过使用字符串替换来清理,以避免每次都打开和关闭字符串。即使是简单的文本替换,我也更喜欢使用replace而不是字符串连接。

这是一个简单的函数,它接受一个键和替换值的对象,并在字符串中替换它们。它假设键是以$为前缀的,以表示它们是一个特殊值。它不进行任何转义或处理$出现在替换值中的边缘情况,等等。

代码语言:javascript
复制
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对象的映射。

代码语言:javascript
复制
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方法比上面的方法更具可读性,但它肯定更易于维护,因为我们不必跟踪开始/结束引号和大量加号。

代码语言:javascript
复制
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 templating

代码语言: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
});
票数 14
EN

Stack Overflow用户

发布于 2015-04-24 09:43:14

如果您希望在代码中保留引用,则应该使用createElement。InnerHTML有时会创建一个很难发现的bug。

HTML代码:

代码语言:javascript
复制
<p id="parent">sample <span id='test'>text</span> about anything</p>

JS代码:

代码语言:javascript
复制
var test = document.getElementById("test");

test.style.color = "red"; //1 - it works

document.getElementById("parent").innerHTML += "whatever";

test.style.color = "green"; //2 - oooops

1)您可以更改颜色

2)你不能再改变颜色或其他任何东西了,因为在上面的代码行中,你向innerHTML添加了一些东西,所有的东西都被重新创建了,你可以访问一些不再存在的东西。为了改变它,你必须再次使用getElementById。

您需要记住,它也会影响任何事件。您需要重新应用事件。

InnerHTML是伟大的,因为它更快,大多数时候更容易阅读,但你必须小心使用它。如果你知道你在做什么,你就会好起来的。

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2946656

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档