简体   繁体   English

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

[英]Creating a new DOM element from an HTML string using built-in DOM methods or Prototype

I have an HTML string representing an element: '<li>text</li>' .我有一个代表元素的 HTML 字符串: '<li>text</li>' I'd like to append it to an element in the DOM (a ul in my case).我想将它附加到 DOM 中的一个元素(在我的例子中是一个ul )。 How can I do this with Prototype or with DOM methods?我如何使用 Prototype 或 DOM 方法来做到这一点?

(I know i could do this easily in jQuery, but unfortunately we're not using jQuery.) (我知道我可以在 jQuery 中轻松做到这一点,但不幸的是我们没有使用 jQuery。)

Note: most current browsers support HTML <template> elements, which provide a more reliable way of turning creating elements from strings.注意:当前大多数浏览器都支持 HTML <template>元素,它提供了一种更可靠的方法来将创建元素从字符串转换为字符串。 See Mark Amery's answer below for details .有关详细信息,请参阅下面的 Mark Amery 的回答

For older browsers, and node/jsdom : (which doesn't yet support <template> elements at the time of writing), use the following method.对于较旧的浏览器和 node/jsdom :(在撰写本文时尚不支持<template>元素),请使用以下方法。 It's the same thing the libraries use to do to get DOM elements from an HTML string ( with some extra work for IE to work around bugs with its implementation of innerHTML ):这与库用来从 HTML 字符串获取 DOM 元素的事情相同( IE需要做一些额外的工作来解决其实现innerHTML错误):

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; 
}

Note that unlike HTML templates this won't work for some elements that cannot legally be children of a <div> , such as <td> s.请注意,与 HTML 模板不同,这不适用于某些不能合法成为<div>子元素的元素,例如<td> s。

If you're already using a library, I would recommend you stick to the library-approved method of creating elements from HTML strings:如果您已经在使用库,我建议您坚持使用库批准的从 HTML 字符串创建元素的方法:

HTML 5 introduced the <template> element which can be used for this purpose (as now described in the WhatWG spec andMDN docs ). HTML 5 引入了可用于此目的的<template>元素(如现在在WhatWG 规范MDN 文档中所述)。

A <template> element is used to declare fragments of HTML that can be utilized in scripts. <template>元素用于声明可在脚本中使用的 HTML 片段。 The element is represented in the DOM as a HTMLTemplateElement which has a .content property of DocumentFragment type, to provide access to the template's contents.该元素在 DOM 中表示为HTMLTemplateElement ,它具有DocumentFragment类型的.content属性,以提供对模板内容的访问。 This means that you can convert an HTML string to DOM elements by setting the innerHTML of a <template> element, then reaching into the template 's .content property.这意味着您可以通过设置<template>元素的innerHTML ,然后访问template.content属性,将 HTML 字符串转换为 DOM 元素。

Examples:例子:

/**
 * @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>');

Note that similar approaches that use a different container element such as a div don't quite work.请注意,使用不同容器元素(例如div类似方法不太适用。 HTML has restrictions on what element types are allowed to exist inside which other element types; HTML 对哪些元素类型允许存在于哪些其他元素类型中有限制; for instance, you can't put a td as a direct child of a div .例如,您不能将td作为div的直接子级。 This causes these elements to vanish if you try to set the innerHTML of a div to contain them.如果您尝试将divinnerHTML设置为包含这些元素,这会导致这些元素消失。 Since <template> s have no such restrictions on their content, this shortcoming doesn't apply when using a template.由于<template>对它们的内容没有这样的限制,所以在使用模板时这个缺点不适用。

However, template is not supported in some old browsers.但是,某些旧浏览器不支持template As of April 2021, Can I use... estimates 96% of users globally are using a browser that supports template s .截至 2021 年 4 月, Can I use...估计全球 96% 的用户都在使用支持template s 的浏览器 In particular, no version of Internet Explorer supports them;特别是,没有任何版本的 Internet Explorer 支持它们; Microsoft did not implement template support until the release of Edge.微软直到 Edge 发布才实现template支持。

If you're lucky enough to be writing code that's only targeted at users on modern browsers, go ahead and use them right now.如果您有幸编写仅针对现代浏览器用户的代码,请立即使用它们。 Otherwise, you may have to wait a while for users to catch up.否则,您可能需要等待一段时间才能让用户跟上。

Use insertAdjacentHTML() .使用insertAdjacentHTML() It works with all current browsers, even with IE11.它适用于所有当前浏览器,甚至适用于 IE11。

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

No need for any tweak, you got a native API:无需任何调整,您就有了一个原生 API:

const toNodes = html =>
    new DOMParser().parseFromString(html, 'text/html').body.childNodes[0]

Newer DOM implementations have range.createContextualFragment , which does what you want in a framework-independent way.较新的 DOM 实现具有range.createContextualFragment ,它以独立于框架的方式执行您想要的操作。

It's widely supported.它得到了广泛的支持。 To be sure though, check its compatibility down in the same MDN link, as it will be changing.不过可以肯定的是,在同一个 MDN 链接中检查它的兼容性,因为它会发生变化。 As of May 2017 this is it:截至 2017 年 5 月,情况如下:

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

For certain html fragments like <td>test</td> , div.innerHTML, DOMParser.parseFromString and range.createContextualFragment (without the right context) solutions mentioned in other answers here, won't create the <td> element.对于此处其他答案中提到的某些 html 片段,如<td>test</td> 、 div.innerHTML、 DOMParser.parseFromString 和 range.createContextualFragment (没有正确的上下文)解决方案,不会创建<td>元素。

jQuery.parseHTML() handles them properly (I extracted jQuery 2's parseHTML function into an independent function that can be used in non-jquery codebases). jQuery.parseHTML() 正确处理它们(我将jQuery 2 的 parseHTML 函数提取到一个可以在非 jquery 代码库中使用的独立函数中)。

If you are only supporting Edge 13+, it is simpler to just use the HTML5 template tag:如果你只支持 Edge 13+,使用 HTML5 模板标签更简单:

function parseHTML(html) {
    var t = document.createElement('template');
    t.innerHTML = html;
    return t.content;
}

var documentFragment = parseHTML('<td>Test</td>');

Heres a simple way to do it:这是一个简单的方法:

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

You can create valid DOM nodes from a string using:您可以使用以下方法从字符串创建有效的 DOM 节点:

document.createRange().createContextualFragment()

The following example adds a button element in the page taking the markup from a string:以下示例在页面中添加一个按钮元素,该元素从字符串中获取标记:

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

I am using this method (Works in IE9+), although it will not parse <td> or some other invalid direct childs of body:我正在使用这种方法(在 IE9+ 中有效),尽管它不会解析<td>或其他一些无效的 body 直接子代:

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>

With Prototype, you can also do:使用 Prototype,您还可以执行以下操作:

HTML: HTML:

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

JS: JS:

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

Why don't do with native js?为什么不用原生js呢?

    var s="<span class='text-muted' style='font-size:.75em; position:absolute; bottom:3px; left:30px'>From <strong>Dan's Tools</strong></span>"
    var e=document.createElement('div')
    var r=document.createRange();
    r.selectNodeContents(e)
    var f=r.createContextualFragment(s);
    e.appendChild(f);
    e = e.firstElementChild;

To enhance furthermore the useful .toDOM() snippet that we can find in different places, we can now safely use backticks ( template literals ).为了进一步增强我们可以在不同地方找到的有用的.toDOM()片段,我们现在可以安全地使用反引号模板文字)。

So we can have single and double quotes in the foo html declaration.所以我们可以在foo html 声明中使用单引号和双引号。

This behave like heredocs for those familiar with the term.对于那些熟悉这个术语的人来说,这就像heredocs

This can be enhanced furthermore with variables, to make complex templating:这可以通过变量进一步增强,以制作复杂的模板:

Template literals are enclosed by the back-tick (`) (grave accent) character instead of double or single quotes.模板文字由反引号 (`)(重音符号)字符而不是双引号或单引号括起来。 Template literals can contain placeholders.模板文字可以包含占位符。 These are indicated by the dollar sign and curly braces (${expression}).这些由美元符号和花括号 (${expression}) 表示。 The expressions in the placeholders and the text between them get passed to a function.占位符中的表达式和它们之间的文本被传递给一个函数。 The default function just concatenates the parts into a single string.默认函数只是将这些部分连接成一个字符串。 If there is an expression preceding the template literal (tag here), this is called a "tagged template".如果在模板文字(此处为标记)之前有一个表达式,则称为“标记模板”。 In that case, the tag expression (usually a function) gets called with the processed template literal, which you can then manipulate before outputting.在这种情况下,标记表达式(通常是一个函数)会使用处理过的模板文字被调用,然后您可以在输出之前对其进行操作。 To escape a back-tick in a template literal, put a backslash \\ before the 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 literals var a = 10, b = 5 var foo=` <img onclick="alert('The future starts today!')" src='//placekitten.com/100/100'> foo${a + b} <i>bar</i> <hr>`.toDOM(); document.body.appendChild(foo);
 img {cursor: crosshair}

So, why not use directly .innerHTML += ?那么,为什么不直接使用.innerHTML +=呢? By doing so, the whole DOM is being recalculated by the browser, it's much slower.通过这样做,整个 DOM 正在由浏览器重新计算,速度要慢得多。

https://caniuse.com/template-literals https://caniuse.com/template-literals

Answer回答

  • Create a Template创建Template
  • Set the Template's innerHTML to your string .trim()Template's innerHTML 设置为您的string .trim()
  • Create an Array of Template's children创建一个Template's孩子Array
  • Return children , child , or返回childrenchild

 function toElement(s='',c,t=document.createElement('template'),l='length'){ t.innerHTML=s.trim();c=[...t.content.childNodes];return c[l]>1?c:c[0]||'';} console.log(toElement()); console.log(toElement('')); console.log(toElement(' ')); console.log(toElement('<td>With td</td>')); console.log(toElement('<tr><td>With t</td></tr>')); console.log(toElement('<tr><td>foo</td></tr><tr><td>bar</td></tr>')); console.log(toElement('<div><span>nested</span> <span>stuff</span></div>'));

I added a Document prototype that creates an element from string:我添加了一个Document原型,它从字符串创建一个元素:

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

HTML5 & ES6 HTML5 & ES6

<template>

Demo演示

 "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>

Late but just as a note;迟到但只是作为一个笔记;

It's possible to add a trivial element to target element as a container and remove it after using.可以将一个平凡的元素作为容器添加到目标元素并在使用后将其删除。

// Tested on chrome 23.0, firefox 18.0, ie 7-8-9 and opera 12.11. // 在 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>

Fastest solution to render DOM from string:从字符串渲染 DOM 的最快解决方案:

let render = (relEl, tpl, parse = true) => {
  if (!relEl) return;
  const range = document.createRange();
  range.selectNode(relEl);
  const child = range.createContextualFragment(tpl);
  return parse ? relEl.appendChild(child) : {relEl, el};
};

And here u can check performance for DOM manipulation React vs native JS在这里你可以检查 DOM 操作 React 与原生 JS 的性能

Now u can simply use:现在你可以简单地使用:

let element = render(document.body, `
<div style="font-size:120%;line-height:140%">
  <p class="bold">New DOM</p>
</div>
`);

And of course in near future u use references from memory cause var "element" is your new created DOM in your document.当然,在不久的将来,您会使用内存中的引用,因为 var "element" 是您在文档中新创建的 DOM。

And remember "innerHTML=" is very slow :/记住“innerHTML=”很慢:/

Here's my code, and it works:这是我的代码,它有效:

function parseTableHtml(s) { // s is string
    var div = document.createElement('table');
    div.innerHTML = s;

    var tr = div.getElementsByTagName('tr');
    // ...
}

For the heck of it I thought I'd share this over complicated but yet simple approach I came up with... Maybe someone will find something useful.对于它,我想我会通过我想出的复杂但简单的方法来分享这个......也许有人会发现一些有用的东西。

/*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')"
}));

I've linked from this article.我从这篇文章链接。 ( Converting HTML string into DOM elements? ) 将 HTML 字符串转换为 DOM 元素?

For me, I want to find a way to convert a string into an HTML element.对我来说,我想找到一种将字符串转换为 HTML 元素的方法。 If you also have this need, you can try the following如果你也有这个需求,可以试试下面的

 const frag = document.createRange().createContextualFragment( `<a href="/link.js">js</a> <a>go</a> ` ) const aCollection = frag.querySelectorAll("a") for (let [key, a] of Object.entries(aCollection)) { console.log(a.getAttribute("href"), a.textContent) }

I have searched a lot for this myself and came across this solution which is neat.我自己为此搜索了很多,并遇到了这个简洁的解决方案。

const stringToHTML = (str) => {
    var parser = new DOMParser();
    var doc = parser.parseFromString(str, 'text/html');
    return doc.body;
};

String that I wanted to convert:我想转换的字符串:

'<iframe src="https://player.vimeo.com/video/578680903?h=ea840f9223&amp;app_id=122963" width="640" height="360" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen title="Total Body Balance"></iframe>'

The result:结果:

<body><iframe src="https://player.vimeo.com/video/578680903?h=ea840f9223&amp;app_id=122963" width="640" height="360" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen="" title="Total Body Balance"></iframe></body>

Example with latest JS:最新 JS 示例:

<template id="woof-sd-feature-box">
<div class="woof-sd-feature-box" data-key="__KEY__" data-title="__TITLE__" data-data="__OPTIONS__">
    <h4>__TITLE__</h4>
    <div class="woof-sd-form-item-anchor">
        <img src="img/move.png" alt="">
    </div>
</div>

</template>

<script>
create(example_object) {
        let html = document.getElementById('woof-sd-feature-box').innerHTML;
        html = html.replaceAll('__KEY__', example_object.dataset.key);
        html = html.replaceAll('__TITLE__', example_object.dataset.title);
        html = html.replaceAll('__OPTIONS__', example_object.dataset.data);
        //convertion HTML to DOM element and prepending it into another element
        const dom = (new DOMParser()).parseFromString(html, "text/html");
        this.container.prepend(dom.querySelector('.woof-sd-feature-box'));
    }
</script>

Solution - works with all browsers since IE 4.0解决方案- 适用于 IE 4.0 以来的所有浏览器

var htmlString = `<body><header class="text-1">Hello World</header><div id="table"><!--TABLE HERE--></div></body>`;
var insertTableString = `<table class="table"><thead><tr><th>th cell</th></tr></thead><tbody><tr><td>td cell</td></tr></tbody></table>`;


var doc = document.implementation.createHTMLDocument();
    doc.open();
    doc.write(htmlString);
    doc.getElementById('table').insertAdjacentHTML('beforeend', tableString);
    doc.close();

console.log(doc);

Or you can use DOMParser或者你可以使用DOMParser

var doc = (new DOMParser).parseFromString(htmlString, "text/html");
    doc.getElementById('table').insertAdjacentHTML('beforeend', tableString);

console.log(doc);
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);

You can use DOM parser:您可以使用 DOM 解析器:

const parser = new DOMParser();
const htmlString = "<strong>Beware of the leopard</strong>";
const doc3 = parser.parseFromString(htmlString, "text/html");

Reference 参考

Visit https://www.codegrepper.com/code-examples/javascript/convert+a+string+to+html+element+in+js访问https://www.codegrepper.com/code-examples/javascript/convert+a+string+to+html+element+in+js

const stringToHtml = function (str) {
    var parser = new DOMParser();
    var doc = parser.parseFromString(str, 'text/html');
    return doc.body;
}

You can use the following function to convert the text "HTML" to the element您可以使用以下函数将文本“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);

Here is working code for me这是我的工作代码

I wanted to convert ' Text ' string to HTML element我想将“文本”字符串转换为 HTML 元素

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

var msg = "test" jQuery.parseHTML(msg)

var jtag = $j.li({ child:'text' }); // Represents: <li>text</li>
var htmlContent = $('mylist').html();
$('mylist').html(htmlContent + jtag.html());

Use jnerator使用jner

This will work too:这也将起作用:

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

It feels more like a jquery way with the chained function calls.感觉更像是带有链式函数调用的 jquery 方式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM