将HTML字符串转换为DOM元素?

310

有没有一种方法可以将类似以下的HTML转换为:

<div>
<a href="#"></a>
<span></span>
</div>

如何将任何其他 HTML 字符串转换为 DOM 元素?(这样我就可以使用 appendChild() 了)。我知道可以使用 .innerHTML 和 .innerText,但那不是我想要的--我真的想能够将动态 HTML 字符串转换为 DOM 元素,以便我可以在 .appendChild() 中传递它。

更新:似乎有些混淆。我在 JavaScript 中有一个变量值作为字符串的HTML内容。文档中没有HTML内容。


7
请看这个链接:https://dev59.com/nnRB5IYBdhLWcg3w1Kr0。它告诉你如何使用内置的DOM方法从HTML字符串中创建新的DOM元素,翻译后尽量保持原意并让内容易于理解。 - jhleath
如果你想要更接近HTML而不是node,我建议使用以下函数 ;) var stringToHTML = function (str) { var dom = document.createElement('div'); dom.innerHTML = str; return dom; }; - La pach'
10个回答

509

你可以使用DOMParser,例如:

var xmlString = "<div id='foo'><a href='#'>Link</a><span></span></div>";
var doc = new DOMParser().parseFromString(xmlString, "text/xml");
console.log(doc.firstChild.innerHTML); // => <a href="#">Link...
console.log(doc.firstChild.firstChild.innerHTML); // => Link


3
谢谢,它很有效。在阅读Mozilla文章后,我意识到浏览器也可以解析XML AJAX响应--因此像IE这样不支持DOMParser的浏览器,我使用同步AJAX调用和数据URI来解析XML. :) - Tower
10
如果您因为尝试加载 HTML 而不是 XML (例如 <br> 标签)而出现错误,请查看此处:https://developer.mozilla.org/zh-CN/docs/Web/API/DOMParser#DOMParser_HTML_extension_for_other_browsers 中的“其他浏览器的DOMParser HTML扩展”部分,以支持加载HTML。 - HMR
15
为什么不能只说“text/html”来解析HTML呢? - John Strood
11
你可以这样做,但会自动生成“html”和“body”标签。 - akauppi
34
注意:我发现如果将创建的节点放回浏览器的DOM(Safari 9.1.2),使用“text/html”而不是“text/xml”非常重要。否则,CSS渲染会出现问题。如果你使用它,请使用“.body”来绕过自动插入的body元素。 - akauppi
显示剩余12条评论

262

通常你会创建一个临时的父元素,将 innerHTML 写入其中,然后提取其内容:

var wrapper= document.createElement('div');
wrapper.innerHTML= '<div><a href="#"></a><span></span></div>';
var div= wrapper.firstChild;
如果你得到的外部HTML元素是一个简单的
,那么这很容易处理。但如果它可能是其他不能随便放置的元素,你可能会遇到更多问题。例如,如果它是一个
  • ,则父包装器必须是一个

      但IE不能在像这样的元素上编写innerHTML,所以如果你有一个,你需要将整个HTML字符串包装在...
      中,将其写入innerHTML中,并从几个层次下面提取实际的。

  • 17
    这个解决方案很可能更具可移植性。 - maerics
    5
    请记住,这种方法会丢失之前分配的任何事件处理程序或其他属性。 - bryc
    18
    @bryc 如何将事件处理程序附加到字符串? - Muhammad Umer
    如果字符串是这样的 some string at the start <div><a href="#">anchor text</a><span>inner text</span></div>string end,该怎么办? - Ari
    此功能不支持包含 <body> 元素的 HTML 字符串。 - Sam Denty
    显示剩余4条评论

    85

    为什么不使用insertAdjacentHTML呢?

    例如:

    // <div id="one">one</div> 
    var d1 = document.getElementById('one'); 
    d1.insertAdjacentHTML('afterend', '<div id="two">two</div>');
    
    // At this point, the new structure is:
    // <div id="one">one</div><div id="two">two</div>here
    

    4
    你知道为了让这个功能正常工作,你需要将该元素放在DOM中吗?而且其实你并不想将该元素放在DOM中,你只是想将一个字符串转换成内存中的HTML。 - vsync
    1
    嗯,@vsync,这确实是MDN文档所说的,但听起来有点可疑,因为这个函数没有理由关心目标节点是否在DOM中。使用今天的浏览器(Chrome),我刚刚测试了一下,不需要在DOM中。任何具有父级的节点都可以使insertAdjacentHTML()非常愉快。不知道其他浏览器是否会有不同的行为... - Ron Burk

    17

    可以查看John Resig的纯JavaScript HTML解析器

    编辑:如果您想让浏览器为您解析HTML,innerHTML正是您想要的。来自这个SO问题

    var tempDiv = document.createElement('div');
    tempDiv.innerHTML = htmlString;
    

    在编写示例时,我注意到简单的HTML标记可以正确地呈现(在IE7上),但是当我尝试使用脚本来实现时(这是我正在处理的情况),脚本无法正常工作。 示例:[Fiddle](http://jsfiddle.net/xETGh/)。您可能需要在本地HTML页面上运行代码(jsfiddle与IE7不兼容)。 - Yuval
    这段代码有一个小问题:如果 htmlString 中包含 <tr>...</tr>,它将无法正常工作 :( - Aikon Mogwai

    6

    好的,我自己想明白了答案,这是在思考其他人的回答之后得出的。:P


    (涉及IT技术相关内容,无法提供更多信息)
    var htmlContent = ... // a response via AJAX containing HTML
    var e = document.createElement('div');
    e.setAttribute('style', 'display: none;');
    e.innerHTML = htmlContent;
    document.body.appendChild(e);
    var htmlConvertedIntoDom = e.lastChild.childNodes; // the HTML converted into a DOM element :), now let's remove the
    document.body.removeChild(e);
    

    11
    您无需在文档中添加“e”。您也不需要对其执行setAttribute操作。 - user52898

    2

    这里有一段非常有用的代码。

    var uiHelper = function () {
    
    var htmls = {};
    
    var getHTML = function (url) {
                    /// <summary>Returns HTML in a string format</summary>
                    /// <param name="url" type="string">The url to the file with the HTML</param>
    
        if (!htmls[url])
        {
        var xmlhttp = new XMLHttpRequest();
        xmlhttp.open("GET", url, false);
        xmlhttp.send();
        htmls[url] = xmlhttp.responseText;
         };
         return htmls[url];
        };
    
            return {
                getHTML: getHTML
            };
    }();
    

    --将HTML字符串转换为DOM元素

    String.prototype.toDomElement = function () {
    
            var wrapper = document.createElement('div');
            wrapper.innerHTML = this;
            var df= document.createDocumentFragment();
            return df.addChilds(wrapper.children);
    };
    

    --原型帮助器

    HTMLElement.prototype.addChilds = function (newChilds) {
            /// <summary>Add an array of child elements</summary>
            /// <param name="newChilds" type="Array">Array of HTMLElements to add to this HTMLElement</param>
            /// <returns type="this" />
            for (var i = 0; i < newChilds.length; i += 1) { this.appendChild(newChilds[i]); };
            return this;
    };
    

    --用法

     thatHTML = uiHelper.getHTML('/Scripts/elevation/ui/add/html/add.txt').toDomElement();
    

    2
    这基本上就是@orip的答案,只是加了很多完全不必要的垃圾代码,并扩展了原生StringHTMLElement的原型(通常你不应该这样做)。这是无关紧要的,甚至有点危险... - aendra
    @aendrew 这是两个不同的例子。原型帮助器恰好是我整个解决方案中最好的帮助器之一,我传递一个DOM元素数组[ele,ele,ele,ele,ele],所以我不同意。而且,第一个转换为DOM元素也很棒。了解更多关于DocumentFragment的知识,“没有人使用”,你就会明白发生了什么。这些都是工具函数。这就是当今开发者的问题所在,如果不是第三方,他们就一无所知。我从头开始编写所有的JS代码。 - Filling The Stack is What I DO
    并且为了进一步阐述我的上一个评论,性能在我大多数的JS应用程序中都是需要认真对待的。 - Filling The Stack is What I DO
    2
    我只是在说不要污染内置对象的原型。这被认为是最佳实践,与从头编写JS、使用库或性能完全无关——它是为了防止后续出现错误。 - aendra
    @FillingTheStackisWhatIDO,除了后者返回节点数组之外,从toDomElement返回wrapper.firstChild和返回df.addChilds(wrapper.children)有什么区别? - Tamil Vendhan Kanagarasu

    1

    只需为元素提供一个id并正常处理即可,例如:

    <div id="dv">
    <a href="#"></a>
    <span></span>
    </div>
    

    现在你可以这样做:

    var div = document.getElementById('dv');
    div.appendChild(......);
    

    或者使用jQuery:

    $('#dv').get(0).appendChild(........);
    

    这是你提供的一个jQuery示例。我认为@rFactor正在寻找一个更直接的Javascript示例。 - darcy
    3
    在你给我负面评价之前,你应该已经看到我已经举了一个纯JavaScript的例子。 - Sarfraz
    2
    示例不起作用,因为它适用于已经存在的DOM元素。当然,如果元素已经是一个DOM元素,则情况很简单,但在我的情况下,HTML内容是变量的值,而不是DOM的一部分。 - Tower
    @rFactor - 你愿意/能够使用jQuery吗?如果你会用它,把HTML字符串解析成DOM元素就非常简单了。 - John Rasch
    我不使用 jQuery,但是所有 jQuery 可以做的事情都可以用纯 JavaScript 实现,所以,如果你有任何例子,请告诉我。嗯,实际上我觉得我自己找到了答案。:P - Tower

    1
    你可以这样做:

    String.prototype.toDOM=function(){
      var d=document
         ,i
         ,a=d.createElement("div")
         ,b=d.createDocumentFragment();
      a.innerHTML=this;
      while(i=a.firstChild)b.appendChild(i);
      return b;
    };
    
    var foo="<img src='//placekitten.com/100/100'>foo<i>bar</i>".toDOM();
    document.body.appendChild(foo);
    

    0
    总结:
    1. 创建一个不可见的元素
    2. 将HTML添加到其中
    3. 通过获取其第一个子节点来获取该元素

    function txtToElem(txt){
    let a = document.createElement('div')
    a.style.display='none'
    document.body.appendChild(a)
    a.innerHTML=txt
    let b = a.children
    document.body.removeChild(a)
    return b
    }
    
    let htmltext='<span>hello sir</span>'
    console.log(txtToElem(htmltext))
    //testing that it works as an elem:
    document.body.appendChild(txtToElem(htmltext)[0])
    <h1>the rest of the website...</h1>

    首先,在文档中添加一个div,通过使用“hide”CSS属性使其不可见。
    然后,使用appendChild()将文本附加到不可见的div中。
    最后,使用Element.children属性获取不可见div内的元素。
    注意:
    将a.children替换为a.childnodes以获取嵌套元素。
    缺点:
    仅适用于前端应用程序。

    -3

    或者,您还可以在将HTML转换为字符串时对其进行包装,使用以下方法:

    JSON.stringify()
    

    以后当您想要从HTML字符串中解包HTML时,请使用

    JSON.parse()
    

    这绝对不是正确的方法。 - Deepak paramesh

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