使用JavaScript插入HTML元素

118

使用以下语法时,不必为每种类型的属性和事件费力地搜索解决方法:

elem = document.createElement("div");
elem.id = 'myID';
elem.innerHTML = ' my Text '
document.body.insertBefore(elem,document.body.childNodes[0]);

有没有一种方法可以将整个HTML元素声明为字符串?例如:

elem = document.createElement("<div id='myID'> my Text </div>");
document.body.insertBefore(elem,document.body.childNodes[0]);
7个回答

136

与其直接操作 innerHTML ,创建一个文档片段并将其插入可能更好:

function create(htmlStr) {
    var frag = document.createDocumentFragment(),
        temp = document.createElement('div');
    temp.innerHTML = htmlStr;
    while (temp.firstChild) {
        frag.appendChild(temp.firstChild);
    }
    return frag;
}

var fragment = create('<div>Hello!</div><p>...</p>');
// You can use native DOM methods to insert the fragment:
document.body.insertBefore(fragment, document.body.childNodes[0]);

好处:

  1. 您可以使用原生DOM方法进行插入,如insertBefore、appendChild等。
  2. 在它们被插入之前,您可以访问实际的DOM节点;您可以访问片段的childNodes对象。
  3. 使用文档片段非常快速;比在DOM外创建元素和在某些情况下比innerHTML更快。

尽管函数中使用了innerHTML,但所有操作都发生在DOM之外,所以比您想象的要快得多...


3
我敢打赌,这个 createDocumentFragment() 方法不如“传统”的 innerHTML 好用。 - Robin Rodricks
2
这种方法适用于所有现代浏览器。 对于IE 5.5及以下版本,您可以执行如下检查: if(document.createDocumentFragment){ create('...'); } else { /或许使用innerHTML/ } - James
正是我的观点,谢谢你提供的代码片段!我喜欢你的方法,因为它很快,所以让所有现代浏览器都采用这种行为作为默认行为是更可取的。 - Robin Rodricks
39
我帮忙 SO 是因为我享受帮助别人;如果解决方案在所有情况下都不是100%可行,那我很抱歉。如果你这么关心,为什么不提供自己的解决方案,而是对已经提供的答案进行不必要的批评?任何抽象都会存在边缘情况!这是一个学习环境 - 我们不在这里为人们提供一揽子解决方案 - 我们在这里互相帮助变得更好!还有抱歉,但有人提到过 "AJAX" 吗? - James
1
好的。我道歉。我只是感觉这里有很多抽象概念,却没有提到任何警告。 - Crescent Fresh
显示剩余2条评论

98
你想要这个。
document.body.insertAdjacentHTML( 'afterbegin', '<div id="myID">...</div>' );

@JonnyLeeds,这似乎在 body 元素上不起作用,但在任何其他元素上都可以正常工作。 - Phill
1
@Phill 当然它可以在 <body> 上运行。事实上,通过控制台将诸如样式表等内容注入到网页中的标准方法是在 <body> 上运行它。您遇到了什么问题? - Šime Vidas
1
@ŠimeVidas 可能是因为在执行时未定义 body 元素... 我将你的代码与 window.onload = function() { ... } 配对,以防止这个问题。 - GDY
@Grandy Phill写道它适用于其他元素。如果<body>未定义,则所有其他元素也将未定义,因此这可能不是Phill的问题。 - Šime Vidas
@ŠimeVidas 嗯,没错...如果它在任何地方都能工作,那么它也应该在 body 上工作。 - GDY
太好了!不过很遗憾,可能是因为我在一个表格中,所以我插入的内容中的所有HTML标签都被去掉了... - xeruf

40

看一下insertAdjacentHTML

var element = document.getElementById("one");
var newElement = '<div id="two">two</div>'
element.insertAdjacentHTML( 'afterend', newElement )
// new DOM structure: <div id="one">one</div><div id="two">two</div>

position是相对于您要插入相邻元素的位置:

'beforebegin' 在元素本身之前

'afterbegin' 在元素内部,在其第一个子元素之前

'beforeend' 在元素内部,在其最后一个子元素之后

'afterend' 在元素本身之后


17

在旧版的JavaScript中,您可以这样做:

document.body.innerHTML = '<p id="foo">Some HTML</p>' + document.body.innerHTML;

回答你的评论:

[...] 我对声明新元素的属性和事件的来源感兴趣,而不是一个元素的 innerHTML。

但你需要将新的HTML注入到DOM中;这就是旧式JavaScript示例中使用innerHTML的原因。BODY元素的innerHTML被插入了新的HTML,并在其前面添加。我们并没有真正改变BODY内部现有的HTML。

我将重写上述示例以澄清这一点:

var newElement = '<p id="foo">This is some dynamically added HTML. Yay!</p>';
var bodyElement = document.body;
bodyElement.innerHTML = newElement + bodyElement.innerHTML;
// note that += cannot be used here; this would result in 'NaN'

使用JavaScript框架可以使得这段代码更加简洁,提高可读性。例如,jQuery 使您可以执行以下操作:

$('body').prepend('<p id="foo">Some HTML</p>');

1
document.getElementsByTagName('body')[0] 的确可以被 document.body 替代,说得好。然而,如果你想将新的 HTML 添加到另一个已存在的元素之前或之后,而不是添加到 BODY 中,你就必须使用 document.getElementById() 和/或 document.getElementsByTagName();这就是为什么我在示例中使用它的原因。 - Mathias Bynens
1
此外,如果您直接添加/插入“innerHTML”,您的代码很快就会变得非常混乱。 - James
1
@JimmyP:什么废话!这个问题的目的就是为了能够直接将HTML作为字符串插入,而不是通过函数来构建它,属性与属性,节点与节点,元素与元素。 - Robin Rodricks
1
这会分离所有事件处理程序,可能会导致严重的内存泄漏问题。 - adardesign
@adardesign 当然,但这对于解决 OP 问题的每个可能的解决方案都是正确的(即基于字符串设置整个文档的 HTML)。为什么要点踩? - Mathias Bynens
显示剩余7条评论

1
据我所知,公平地说,我的了解还比较新且有限,这种技术唯一可能存在的问题是您无法动态创建某些表格元素。
我使用一个表单来进行模板化,通过向隐藏的 DIV 添加“模板”元素,然后使用 cloneNode(true) 创建克隆,并根据需要将其附加。请记住,您确实需要确保根据需要重新分配 ID,以防止重复。

1

正如其他人所说,方便的jQuery prepend功能可以模拟:

var html = '<div>Hello prepended</div>';
document.body.innerHTML = html + document.body.innerHTML;

虽然有些人认为最好不要“搞乱”innerHTML,但在许多用例中它是可靠的,只要你知道这个:

如果一个<div><span><noembed>节点有一个包含字符(&)、(<)或(>)的子文本节点,innerHTML将分别返回这些字符:&amp&lt&gt。使用Node.textContent获取这些文本节点内容的正确副本。

https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML

或者:

var html = '<div>Hello prepended</div>';
document.body.insertAdjacentHTML('afterbegin', html)

insertAdjacentHTML 可能是一个不错的替代方案:https://developer.mozilla.org/zh-CN/docs/Web/API/Element/insertAdjacentHTML


因为你指出了textContent,这是将完整HTML从一个节点复制到另一个节点的解决方案,所以我给你点赞了 :) - xeruf

-2
如果你想在现有页面标签中插入HTML代码,请使用Jnerator。这个工具是为了这个目的而创建的。
不要写下面的这段代码
    var htmlCode = '<ul class=\'menu-countries\'><li
        class=\'item\'><img src=\'au.png\'></img><span>Australia </span></li><li
        class=\'item\'><img src=\'br.png\'> </img><span>Brazil</span></li><li
        class=\'item\'> <img src=\'ca.png\'></img><span>Canada</span></li></ul>';
    var element = document.getElementById('myTag');
    element.innerHTML = htmlCode;

你可以编写更易于理解的结构

    var jtag = $j.ul({
        class: 'menu-countries',
        child: [
            $j.li({ class: 'item', child: [
                $j.img({ src: 'au.png' }),
                $j.span({ child: 'Australia' })
            ]}),
            $j.li({ class: 'item', child: [
                $j.img({ src: 'br.png' }),
                $j.span({ child: 'Brazil' })
            ]}),
            $j.li({ class: 'item', child: [
                $j.img({ src: 'ca.png' }),
                $j.span({ child: 'Canada' })
            ]})
        ]
    });
    var htmlCode = jtag.html();
    var element = document.getElementById('myTag');
    element.innerHTML = htmlCode;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接