我知道最近已经讨论了adding innerHTML
to document fragments,并希望将其纳入DOM标准。但是,在此期间您应该使用的解决方法是什么?
即,
var html = '<div>x</div><span>y</span>';
var frag = document.createDocumentFragment();
我希望div
内的span
和frag
都有一个简单的单行内容。
没有循环的奖励积分。允许jQuery,但我已经尝试$(html).appendTo(frag)
;之后frag
仍然是空的。
答案 0 :(得分:82)
这是modern browsers中没有循环的方式:
var temp = document.createElement('template');
temp.innerHTML = '<div>x</div><span>y</span>';
var frag = temp.content;
或作为可重复使用的
function fragmentFromString(strHTML) {
var temp = document.createElement('template');
temp.innerHTML = strHTML;
return temp.content;
}
更新: 我找到了一种更简单的方法来使用Pete的主要想法,它将IE11添加到混合中:
function fragmentFromString(strHTML) {
return document.createRange().createContextualFragment(strHTML);
}
覆盖率优于<template>
方法,并且在IE11,Ch,FF中测试正常。
答案 1 :(得分:24)
目前,仅使用字符串填充文档片段的唯一方法是创建一个临时对象,并遍历子项以将它们附加到片段。
如果要创建整个文档,请改用DOMParser。看看this answer。
代码:
var frag = document.createDocumentFragment(),
tmp = document.createElement('body'), child;
tmp.innerHTML = '<div>x</div><span>y</span>';
while (child = tmp.firstElementChild) {
frag.appendChild(child);
}
单行(两行表示可读性)(输入:String html
,输出:DocumentFragment frag
):
var frag =document.createDocumentFragment(), t=document.createElement('body'), c;
t.innerHTML = html; while(c=t.firstElementChild) frag.appendChild(c);
答案 2 :(得分:10)
使用Range.createContextualFragment:
var html = '<div>x</div><span>y</span>';
var range = document.createRange();
// or whatever context the fragment is to be evaluated in.
var parseContext = document.body;
range.selectNodeContents(parseContext);
var fragment = range.createContextualFragment(html);
请注意,此方法与<template>
方法之间的主要区别是:
Range.createContextualFragment得到了更广泛的支持(IE11刚刚获得它,Safari,Chrome和FF已经有一段时间了)。
HTML中的自定义元素将立即使用范围进行升级,但仅在使用模板克隆到真实文档中时才会升级。模板方法更加“惰性”,这可能是理想的。
答案 3 :(得分:5)
@PAEz指出@ RobW的方法不包括元素之间的文本。那是因为children
只抓取 Elements ,而不是 Nodes 。更强大的方法可能如下:
var fragment = document.createDocumentFragment(),
intermediateContainer = document.createElement('div');
intermediateContainer.innerHTML = "Wubba<div>Lubba</div>Dub<span>Dub</span>";
while (intermediateContainer.childNodes.length > 0) {
fragment.appendChild(intermediateContainer.childNodes[0]);
}
性能可能会因较大的HTML块而受到影响,但是,它与许多旧版浏览器兼容并且简洁。
答案 4 :(得分:2)
createDocumentFragment创建一个空DOM“容器”。 innerHtml和其他方法仅适用于DOM节点(而不是容器),因此您必须先创建节点,然后将它们添加到片段中。您可以使用痛苦的appendChild方法来完成它,或者您可以创建一个节点并修改它的innerHtml并将其添加到您的片段。
var frag = document.createDocumentFragment();
var html = '<div>x</div><span>y</span>';
var holder = document.createElement("div")
holder.innerHTML = html
frag.appendChild(holder)
使用jquery,您只需将html保存并构建为字符串即可。如果你想将它转换为jquery对象来执行jquery之类的操作,只需执行$(html)在内存中创建一个jquery对象。准备好追加它之后,只需将其附加到页面上的现有元素
即可答案 5 :(得分:2)
就像@dandavis所说,使用template-tag有一种标准的方法 但是如果你想支持IE11并且你需要解析像&#39;&lt; td&gt; test&#39;这样的表格元素,你可以使用这个函数:
function createFragment(html){
var tmpl = document.createElement('template');
tmpl.innerHTML = html;
if (tmpl.content == void 0){ // ie11
var fragment = document.createDocumentFragment();
var isTableEl = /^[^\S]*?<(t(?:head|body|foot|r|d|h))/i.test(html);
tmpl.innerHTML = isTableEl ? '<table>'+html : html;
var els = isTableEl ? tmpl.querySelector(RegExp.$1).parentNode.childNodes : tmpl.childNodes;
while(els[0]) fragment.appendChild(els[0]);
return fragment;
}
return tmpl.content;
}
答案 6 :(得分:1)
这是一个x浏览器解决方案,在IE10,IE11,Edge,Chrome和FF上进行了测试。
function HTML2DocumentFragment(markup: string) { if (markup.toLowerCase().trim().indexOf('<!doctype') === 0) { let doc = document.implementation.createHTMLDocument(""); doc.documentElement.innerHTML = markup; return doc; } else if ('content' in document.createElement('template')) { // Template tag exists! let el = document.createElement('template'); el.innerHTML = markup; return el.content; } else { // Template tag doesn't exist! var docfrag = document.createDocumentFragment(); let el = document.createElement('body'); el.innerHTML = markup; for (let i = 0; 0 < el.childNodes.length;) { docfrag.appendChild(el.childNodes[i]); } return docfrag; } }
答案 7 :(得分:1)
我会喜欢这样的东西。
function fragmentFromString(html) {
const range = new Range();
const template = range.createContextualFragment(html);
range.selectNode(template.firstElementChild);
return range;
}
// Append to body
// document.body.append(fragmentFromString(`<div>a</div>`).cloneContents())
通过这种方式,您可以将内容保留在Range对象中,并免费获得所有必需的方法。
您可以在https://developer.mozilla.org/en-US/docs/Web/API/Range
中找到所有Range方法和属性的列表。 注意:完成操作后,请记住使用detatch()
方法,以避免泄漏并提高性能。
答案 8 :(得分:0)
要使用尽可能少的行来执行此操作,您可以将您的内容包装在另一个div中,这样您就不必多次循环或调用appendchild。使用jQuery(如您所述),您可以非常快速地创建一个未连接的dom节点并将其放在片段中。
var html = '<div id="main"><div>x</div><span>y</span></div>';
var frag = document.createDocumentFragment();
frag.appendChild($(html)[0]);
答案 9 :(得分:0)
var html = '<div>x</div><span>y</span>';
var frag = document.createDocumentFragment();
var e = document.createElement('i');
frag.appendChild(e);
e.insertAdjacentHTML('afterend', html);
frag.removeChild(e);
答案 10 :(得分:0)
没有人提供所要求的“简单一线”。
给出变量...
var html = '<div>x</div><span>y</span>';
var frag = document.createDocumentFragment();
…下面的代码可以解决问题(在Firefox 67.0.4中):
frag.append(...new DOMParser().parseFromString(html, "text/html").body.childNodes);