使用 document.createDocumentFragment() 和 innerHTML 来操作 DOM
Posted
技术标签:
【中文标题】使用 document.createDocumentFragment() 和 innerHTML 来操作 DOM【英文标题】:using document.createDocumentFragment() and innerHTML to manipulate a DOM 【发布时间】:2012-01-02 09:13:22 【问题描述】:我正在创建一个文档片段,如下所示:
var aWholehtmlDocument = '<!doctype html> <html><head></head><body><h1>hello world</h1></body></html>';
var frag = document.createDocumentFragment();
frag.innerHTML = aWholeHTMLDocument;
变量aWholeHTMLDocument
包含一个长字符串,它是一个页面的整个html文档,我想将它插入到我的fragment中,以便动态生成和操作DOM。 p>
我的问题是,一旦我将该字符串添加到frag.innerHTML
,它不应该加载该字符串并将其转换为 DOM 对象吗?
设置innerHTML后,我不应该通过属性访问DOM吗?
我尝试了 frag.childNodes 但它似乎不包含任何内容,我只想访问新创建的 DOM。
【问题讨论】:
我不确定任何 DOM 元素的“innerHTML”(文档片段实际上只是一个不能成为 DOM 一部分的 DOM 元素)是否是完整的HTML 文档。如果可能的话,您的问题的答案是“是”。 你只做一次 .innerHTML 而不是 .appendChild(frag) 。它比创建文档片段更快,因为字符串处理更快。 证明:jsperf.com/fragments-vs-html-strings 【参考方案1】:你can't set the innerHTML of a document fragment 就像你对普通节点所做的那样,这就是问题所在。添加标准 div 并设置其 innerHTML 是常见的解决方案。
【讨论】:
那么您的意思是我应该执行以下操作? var aWholeHTMLDocument = 'hello world
'; var div = document.createElement('div'); div.innerHTML = 一个WholeHTMLDocument;这将删除除之外的所有内容...
@Loic - 他从来没有说过这样的话......他只是解释了你的错误。绝对不推荐您在评论中建议的解决方案。【参考方案2】:使用文档片段,您可以附加使用document.createElement('yourElement')
创建的元素。 aWholeHTMLDocument
只是文字。此外,除非您使用框架,否则我不确定您为什么需要创建整个 HTML 文档,只需使用 <body>
标记内的内容即可。
【讨论】:
这是一个 Firefox 插件。我将 aWholeHTMLDocument 放入 iFrame,但我需要它完整,而不仅仅是 标签, 标签还包含感兴趣的东西,我想保持整个 DOM 完整。 @Loic 那么你想要的是获得对iframe
的引用并将其innerHTML 设置为aWholeHTMLDocument
【参考方案3】:
对于 Firefox 插件,使用 document.implementation.createHTMLDocument
方法可能更有意义,然后从提供给您的 DOM 中获取。
【讨论】:
【参考方案4】:我知道这个问题很老了,但我在玩文档片段时遇到了同样的问题,因为我没有意识到我必须向它附加一个 div 并使用 div 的innerHTML
来加载 HTML 字符串并从中获取 DOM 元素。我有其他关于如何做这类事情的答案,更适合整个文档。
在 firefox (23.0.1) 中,设置文档片段的 innerHTML 属性似乎不会自动生成元素。只有在将片段附加到文档之后才会创建元素。
要创建整个文档,请使用document.implementation
方法(如果它们受支持)。我已经在 Firefox 上成功了,但我还没有在其他浏览器上真正测试过。您可以查看 AtropaToolbox 中的 HTMLParser.js 以获取使用 document.implementation
方法的示例。我已经使用这段脚本来处理XMLHttpRequest
页面并对其进行操作或从中提取数据。虽然页面中的脚本没有执行,但这是我想要的,虽然它可能不是你想要的。我使用这种相当冗长的方法而不是尝试直接使用 XMLHttpRequest
对象提供的解析的原因是当时我遇到了很多解析错误的麻烦,我想指定文档应该是被解析为 HTML 4 过渡,因为它似乎采取了各种 slop 并生成 DOM。
还有一个DOMParser
可用,您可能更容易使用它。 Eli Gray 在 MDN 的页面上有一个针对没有 DOMParser
但支持 document.implementation.createHTMLDocument
的浏览器的实现。 DOMParser
的规范指定不执行页面中的脚本,并且呈现 noscript 标记的内容。
如果您确实需要在页面中启用脚本,您可以创建一个高度为 0、宽度为 0、无边框等的 iFrame。它仍然会在页面中,但您可以很好地隐藏它。
您还可以选择使用window.open()
和document.write
、DOM 方法或任何您喜欢的方法。现在有些浏览器甚至允许你做数据 URI。
var x = window.open( 'data:text/html;base64,' + btoa('<h1>hi</h1>') );
// wait for the document to load. It only takes a few milliseconds
// but we'll wait for 5 seconds so you can watch the child window
// change.
setTimeout(function ()
console.log(x.document.documentElement.outerHTML);
x.console.log('this is the console in the child window');
x.document.body.innerHTML = 'oh wow';
, 5000);
因此,您确实有一些选项可以在屏幕外/隐藏创建整个文档并对其进行操作,所有这些都支持从字符串加载文档。
还有phantomjs,这是一个很棒的项目,它产生了一个基于 webkit 的无头可编写脚本的网络浏览器。您将可以访问本地文件系统,并且几乎可以做任何您想做的事情。我真的不知道您要通过整页脚本和操作来完成什么。
【讨论】:
【参考方案5】:使用 querySelector() 来获取文档片段的子项(您可能想要正文,或者正文的某个子项)。然后获取innerHTML。
document.body.innerHTML = aWholeHTMLDocument.querySelector("body").innerHTML
或
aWholeHTMLDocument.querySelector("body").childNodes;
见https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment.querySelector
【讨论】:
【参考方案6】:使用appendChild
见https://developer.mozilla.org/en-US/docs/Web/API/Document/createDocumentFragment
var fragment = document.createDocumentFragment();
... fragment.appendChild(some element);
document.querySelector('blah').appendChild(fragment);
【讨论】:
这不能解决“进程字符串”问题。【参考方案7】:虽然DocumentFragment
不支持innerHTML
,但<template>
支持。
<template>
元素的content
属性是DocumentFragment
,因此其行为方式相同。例如,您可以这样做:
var tpl = document.createElement('template');
tpl.innerHTML = '<tr><td>Hello</td><td>world</td></tr>';
document.querySelector('table').appendChild(tpl.content);
上面的例子很重要,因为你不能用innerHTML
和例如。 <div>
,因为 <div>
不允许 <tr>
元素作为子元素。
注意:DocumentFragment
仍会剥离 <head>
和 <body>
标记,因此它也不会执行您想要的操作。你真的需要创建一个全新的Document
。
【讨论】:
真的,这应该是公认的答案,因为它也提供了一个非常好的解决方案。 @Chowey:table
中的 tr
元素存在于 thead
、tbody
或 tfoot
中。【参考方案8】:
DocumentFragment
继承自 Node
,但不继承自包含 .innerHTML
属性的 Element
。
在你的情况下,我会使用<template>
标签。 In 继承自 Element
,它有一个漂亮的 HTMLTemplateElement.content
属性,可以为您提供 DocumentFragment
。
这是一个您可以使用的简单辅助方法:
export default function StringToFragment(string)
var renderer = document.createElement('template');
renderer.innerHTML = string;
return renderer.content;
【讨论】:
【参考方案9】:这是一个将 HTML 字符串转换为 DOM 对象的解决方案:
let markup = '<!doctype html><html><head></head><body><h1>hello world</h1></body></html>';
let range = document.createRange();
let fragment = range.createContextualFragment(markup); //Creates a DOM object
字符串不必是完整的 HTML 文档。
【讨论】:
以上是关于使用 document.createDocumentFragment() 和 innerHTML 来操作 DOM的主要内容,如果未能解决你的问题,请参考以下文章
在使用加载数据流步骤的猪中,使用(使用 PigStorage)和不使用它有啥区别?
Qt静态编译时使用OpenSSL有三种方式(不使用,动态使用,静态使用,默认是动态使用)