首页 文章

使用内置DOM方法或Prototype从HTML字符串创建新的DOM元素

提问于
浏览
434

我有一个表示元素的HTML字符串: '<li>text</li>' . 我想将它追加到DOM中的一个元素(在我的例子中是 ul ) . 如何使用Prototype或DOM方法执行此操作?

(我知道我可以在jQuery中轻松完成,但不幸的是我们没有使用jQuery . )

21 回答

  • -2

    这也可以:

    $('<li>').text('hello').appendTo('#mylist');
    

    感觉更像是链接函数调用的jquery方式 .

  • 16

    无需任何调整,您有一个原生API:

    const toNodes = html =>
        new DOMParser().parseFromString(html, 'text/html').body.childNodes
    
  • 15

    这是一个简单的方法:

    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);
    
  • 3

    这是我的工作代码

    我想将'Text'字符串转换为HTML元素

    var diva = UWA.createElement('div');
    diva.innerHTML = '<a href="http://wwww.example.com">Text</a>';
    var aelement = diva.firstChild;
    
  • 632

    您可以使用以下函数将文本“HTML”转换为元素

    function htmlToElement(html)
    {
      var element = document.createElement('div');
      element.innerHTML = html;
      return(element);
    }
    var html="<li>text and html</li>";
    var e=htmlToElement(html);
    
  • -1

    您可以使用以下命令从字符串创建有效的DOM节点:

    document.createRange().createContextualFragment()

    以下示例在页面中添加一个按钮元素,从字符串中获取标记:

    let html = '<button type="button">Click Me!</button>';
    let fragmentFromString = function (strHTML) {
      return document.createRange().createContextualFragment(strHTML);
    }
    let fragment = fragmentFromString(html);
    document.body.appendChild(fragment);
    
  • -1

    较新的DOM实现具有range.createContextualFragment,它以与框架无关的方式执行您想要的操作 .

    它得到了广泛的支持 . 但是要确定, check its compatibility 在同一个MDN链接中,因为它将会改变 . 截至2017年5月,这是:

    Feature         Chrome   Edge   Firefox(Gecko)  Internet Explorer   Opera   Safari
    Basic support   (Yes)    (Yes)  (Yes)           11                  15.0    9.1.2
    
  • 10

    使用Prototype,您还可以:

    HTML:

    <ul id="mylist"></ul>
    

    JS:

    $('mylist').insert('<li>text</li>');
    
  • 202

    我正在使用此方法(在IE9中工作),虽然它不会解析 <td> 或其他一些无效的直接子项:

    function stringToEl(string) {
        var parser = new DOMParser(),
            content = 'text/html',
            DOM = parser.parseFromString(string, content);
    
        // return element
        return DOM.body.childNodes[0];
    }
    
    stringToEl('<li>text</li>'); //OUTPUT: <li>text</li>
    
  • 0

    使用insertAdjacentHTML() . 它适用于所有当前的浏览器,即使使用IE11 .

    var mylist = document.getElementById('mylist');
    mylist.insertAdjacentHTML('beforeend', '<li>third</li>');
    
    <ul id="mylist">
     <li>first</li>
     <li>second</li>
    </ul>
    
  • 1

    HTML5 <template>&ES6

    演示

    "use strict";
    
    /**
     *
     * @author xgqfrms
     * @license MIT
     * @copyright xgqfrms
     * @description HTML5 Template
     * @augments
     * @example
     *
     */
    
    /*
    
    <template>
        <h2>Flower</h2>
        <img src="https://www.w3schools.com/tags/img_white_flower.jpg">
    </template>
    
    
    <template>
        <div class="myClass">I like: </div>
    </template>
    
    */
    
    const showContent = () => {
        // let temp = document.getElementsByTagName("template")[0],
        let temp = document.querySelector(`[data-tempalte="tempalte-img"]`),
            clone = temp.content.cloneNode(true);
        document.body.appendChild(clone);
    };
    
    const templateGenerator = (datas = [], debug = false) => {
        let result = ``;
        // let temp = document.getElementsByTagName("template")[1],
        let temp = document.querySelector(`[data-tempalte="tempalte-links"]`),
            item = temp.content.querySelector("div");
        for (let i = 0; i < datas.length; i++) {
            let a = document.importNode(item, true);
            a.textContent += datas[i];
            document.body.appendChild(a);
        }
        return result;
    };
    
    const arr = ["Audi", "BMW", "Ford", "Honda", "Jaguar", "Nissan"];
    
    if (document.createElement("template").content) {
        console.log("YES! The browser supports the template element");
        templateGenerator(arr);
        setTimeout(() => {
            showContent();
        }, 0);
    } else {
        console.error("No! The browser does not support the template element");
    }
    
    @charset "UTf-8";
    
    /* test.css */
    
    :root {
        --cololr: #000;
        --default-cololr: #fff;
        --new-cololr: #0f0;
    }
    
    [data-class="links"] {
        color: white;
        background-color: DodgerBlue;
        padding: 20px;
        text-align: center;
        margin: 10px;
    }
    
    <!DOCTYPE html>
    <html lang="zh-Hans">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Template Test</title>
        <!--[if lt IE 9]>
            <script src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.js"></script>
        <![endif]-->
    </head>
    
    <body>
        <section>
            <h1>Template Test</h1>
        </section>
        <template data-tempalte="tempalte-img">
            <h3>Flower Image</h3>
            <img src="https://www.w3schools.com/tags/img_white_flower.jpg">
        </template>
        <template data-tempalte="tempalte-links">
            <h3>links</h3>
            <div data-class="links">I like: </div>
        </template>
        <!-- js -->
    </body>
    
    </html>
    
  • 24
    function domify (str) {
      var el = document.createElement('div');
      el.innerHTML = str;
    
      var frag = document.createDocumentFragment();
      return frag.appendChild(el.removeChild(el.firstChild));
    }
    
    var str = "<div class='foo'>foo</div>";
    domify(str);
    
  • 6

    HTML 5引入了 <template> 元素,可用于此目的(如WhatWG specMDN docs中所述) .

    <template> 是一个HTML元素,允许任何其他元素类型作为子元素 . template 有一个 .content 属性,您可以使用JavaScript访问该属性,该属性指向带有模板内容的DocumentFragment . 这意味着你可以将一个HTML字符串通过设置 <template> 元素的innerHTML,然后伸到 template.content 属性的DOM元素 .

    例子:

    /**
     * @param {String} HTML representing a single element
     * @return {Element}
     */
    function htmlToElement(html) {
        var template = document.createElement('template');
        html = html.trim(); // Never return a text node of whitespace as the result
        template.innerHTML = html;
        return template.content.firstChild;
    }
    
    var td = htmlToElement('<td>foo</td>'),
        div = htmlToElement('<div><span>nested</span> <span>stuff</span></div>');
    
    /**
     * @param {String} HTML representing any number of sibling elements
     * @return {NodeList} 
     */
    function htmlToElements(html) {
        var template = document.createElement('template');
        template.innerHTML = html;
        return template.content.childNodes;
    }
    
    var rows = htmlToElements('<tr><td>foo</td></tr><tr><td>bar</td></tr>');
    

    请注意,类似的方法use a different container element such as a divtd 作为 div 的直接子项 . 如果您尝试将 divinnerHTML 设置为包含它们,则会导致这些元素消失 . 由于 <template> s对其内容没有此类限制,因此在使用模板时不适用此缺点 .

    但是,某些旧版浏览器不支持 template . 截至2018年1月,我可以使用......估计90% of users globally are using a browser that supports templates . 特别是,没有版本的Internet Explorer支持它们;在Edge发布之前,Microsoft没有实现 template 支持 .

    如果您足够幸运能够编写仅针对现代浏览器用户的代码,请立即使用它们 . 否则,您可能需要等待一段时间才能让用户赶上 .

  • 36

    我添加了一个 Document 原型,它从字符串创建一个元素:

    Document.prototype.createElementFromString = function (str) {
        const element = new DOMParser().parseFromString(str, 'text/html');
        const child = element.documentElement.querySelector('body').firstChild;
        return child;
    };
    
  • 4

    对于它,我想我会分享这个复杂而简单的方法我想出来......也许有人会找到有用的东西 .

    /*Creates a new element - By Jamin Szczesny*/
    function _new(args){
        ele = document.createElement(args.node);
        delete args.node;
        for(x in args){ 
            if(typeof ele[x]==='string'){
                ele[x] = args[x];
            }else{
                ele.setAttribute(x, args[x]);
            }
        }
        return ele;
    }
    
    /*You would 'simply' use it like this*/
    
    $('body')[0].appendChild(_new({
        node:'div',
        id:'my-div',
        style:'position:absolute; left:100px; top:100px;'+
              'width:100px; height:100px; border:2px solid red;'+
              'cursor:pointer; background-color:HoneyDew',
        innerHTML:'My newly created div element!',
        value:'for example only',
        onclick:"alert('yay')"
    }));
    
  • 2
    var jtag = $j.li({ child:'text' }); // Represents: <li>text</li>
    var htmlContent = $('mylist').html();
    $('mylist').html(htmlContent + jtag.html());
    

    使用jnerator

  • 2

    迟到但只是作为一个笔记;

    可以将一个简单的元素添加到目标元素作为容器,并在使用后将其删除 .

    //在chrome 23.0,firefox 18.0,即7-8-9和opera 12.11上测试 .

    <div id="div"></div>
    
    <script>
    window.onload = function() {
        var foo, targetElement = document.getElementById('div')
        foo = document.createElement('foo')
        foo.innerHTML = '<a href="#" target="_self">Text of A 1.</a> '+
                        '<a href="#" onclick="return !!alert(this.innerHTML)">Text of <b>A 2</b>.</a> '+
                        '<hr size="1" />'
        // Append 'foo' element to target element
        targetElement.appendChild(foo)
    
        // Add event
        foo.firstChild.onclick = function() { return !!alert(this.target) }
    
        while (foo.firstChild) {
            // Also removes child nodes from 'foo'
            targetElement.insertBefore(foo.firstChild, foo)
        }
        // Remove 'foo' element from target element
        targetElement.removeChild(foo)
    }
    </script>
    
  • -2

    为了进一步增强有用.toDOM()片断,我们可以在不同的地方找到,现在我们可以放心地使用 backtickstemplate literals) .

    所以我们可以在foo html声明中使用单引号和双引号 .

    对于熟悉该术语的人来说,这表现得像heredocs .

    这可以通过变量进一步增强,以进行复杂的模板化:

    模板文字由back-tick()(重音符号)字符括起,而不是双引号或单引号 . 模板文字可以包含占位符 . 这些由美元符号和花括号($ )表示 . 占位符中的表达式和它们之间的文本将传递给函数 . 默认函数只是将部分连接成一个字符串 . 如果模板文字前面有一个表达式(此处为标记),则称为“标记模板” . 在这种情况下,标记表达式(通常是函数)将使用已处理的模板文字进行调用,然后您可以在输出之前对其进行操作 . 要逃避模板文字中的反向标记,请在反向标记之前添加反斜杠\ .

    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
    }
    
    // Using template litterals
    var a = 10, b = 5
    var foo=`
    <img 
      onclick="alert('The future start today!')"   
      src='//placekitten.com/100/100'>
    foo${a + b}
      <i>bar</i>
        <hr>`.toDOM();
    document.body.appendChild(foo);
    
    img {cursor: crosshair}
    

    https://caniuse.com/template-literals

  • 8

    Note: 最新的浏览器支持HTML <template> 元素,这些元素提供了一种更可靠的方法来转换从字符串创建元素 . 见Mark Amery's answer below for details .

    For older browsers, and node/jsdom :(在编写时尚不支持 <template> 元素),请使用以下方法 . 图书馆用来从HTML字符串中获取DOM元素的方法与此相同(with some extra work for IE通过实现 innerHTML 来解决bug:

    function createElementFromHTML(htmlString) {
      var div = document.createElement('div');
      div.innerHTML = htmlString.trim();
    
      // Change this to div.childNodes to support multiple top-level nodes
      return div.firstChild; 
    }
    

    请注意,与HTML模板不同,这不适用于某些不能合法成为 <div> 子元素的元素,例如 <td> .

    如果您已经在使用库,我建议您坚持使用库批准的方法从HTML字符串创建元素:

  • 1

    这是我的代码,它有效:

    function parseTableHtml(s) { // s is string
        var div = document.createElement('table');
        div.innerHTML = s;
    
        var tr = div.getElementsByTagName('tr');
        // ...
    }
    
  • -5

    对于某些html片段,如 <td>test</td> ,div.innerHTML,DOMParser.parseFromString和range.createContextualFragment(没有正确的上下文)将不会创建 <td> 元素 .

    jQuery.parseHTML()处理它们(我解压jQuery 2's parseHTML function into an independent gist) .

    对于Edge 13,请使用模板标记:

    function parseHTML(html) {
        var t = document.createElement('template');
            t.innerHTML = html;
        return t.content.cloneNode(true);
    }
    
    var documentFragment = parseHTML('<td>Test</td>');
    

相关问题