Javascript 将精确的innerHTML恢复到DOM
我想保存DOM的html字符串,然后将其还原为完全相同的字符串。代码如下所示:Javascript 将精确的innerHTML恢复到DOM,javascript,jquery,html,firefox,dom,Javascript,Jquery,Html,Firefox,Dom,我想保存DOM的html字符串,然后将其还原为完全相同的字符串。代码如下所示: var stringified = document.documentElement.innerHTML // later, after serializing and deserializing document.documentElement.innerHTML = stringified function ruinTheHtml() { var allElements = document.body.get
var stringified = document.documentElement.innerHTML
// later, after serializing and deserializing
document.documentElement.innerHTML = stringified
function ruinTheHtml() {
var allElements = document.body.getElementsByTagName( "*" ),
next,
afterNext;
Array.prototype.map.call( allElements,function( el,i ){
if( el.tagName !== 'SCRIPT' && el.tagName !== 'STYLE' ) {
if(el.textContent === '') {
next = el.nextSibling;
afterNext = next.nextSibling;
if( afterNext.textContent === '' ) {
el.parentNode.removeChild( afterNext );
el.appendChild( next );
}
}
}
});
}
当一切都很完美时,这是可行的,但是当DOM不是w3c兼容时,就会出现问题。第一行工作正常,stringized
与DOM完全匹配。但是,当我从(不符合w3c的)字符串化的
还原时,浏览器发挥了一些神奇的作用,生成的DOM与最初的不一样
例如,如果我的原始DOM看起来像
<p><div></div></p>
这不适用于您最近的澄清,即您必须拥有字符串副本。不过,把它留给其他可能更灵活的人
由于使用DOM似乎可以在某种程度上保留无效的结构,并且使用
innerHTML
会带来(正如您所观察到的)副作用,因此我们必须考虑不使用innerHTML
:
您可以克隆原始文件,然后在克隆中交换:
var e = document.getElementById('asdf')
snippet.log("1: " + e.innerHTML);
var clone = e.cloneNode(true);
var insert = document.createElement('div');
var text = document.createTextNode('ladygaga');
insert.appendChild(text);
document.getElementById('outer').appendChild(insert);
snippet.log("2: " + e.innerHTML);
e.parentNode.replaceChild(clone, e);
e = clone;
snippet.log("3: " + e.innerHTML);
现场示例:
var e=document.getElementById('asdf'))
log(“1:+e.innerHTML”);
var clone=e.cloneNode(真);
var insert=document.createElement('div');
var text=document.createTextNode('ladygaga');
插入.appendChild(文本);
document.getElementById('outer').appendChild(insert);
log(“2:+e.innerHTML”);
e、 parentNode.replaceChild(克隆,e);
e=克隆;
log(“3:+e.innerHTML”)代码>
高清
尝试利用Blob
,URL.createObjectURL
导出html
;在导出的html
中包含script
标记,该标记从呈现的html
文档中删除
元素
html
jshiddle参见以下示例:
您不能期望HTML被解析为不兼容的HTML。但是,由于编译后的不兼容HTML的结构是非常可预测的,您可以创建一个函数,使HTML再次不兼容,如下所示:
var stringified = document.documentElement.innerHTML
// later, after serializing and deserializing
document.documentElement.innerHTML = stringified
function ruinTheHtml() {
var allElements = document.body.getElementsByTagName( "*" ),
next,
afterNext;
Array.prototype.map.call( allElements,function( el,i ){
if( el.tagName !== 'SCRIPT' && el.tagName !== 'STYLE' ) {
if(el.textContent === '') {
next = el.nextSibling;
afterNext = next.nextSibling;
if( afterNext.textContent === '' ) {
el.parentNode.removeChild( afterNext );
el.appendChild( next );
}
}
}
});
}
看小提琴:
您必须克隆节点,而不是复制html。当看到div
时,解析规则将强制浏览器关闭p
如果您确实需要从该字符串获取html,并且它是有效的xml,那么您可以使用以下代码($
isjQuery
):
var html=“”;
var div=document.createElement(“div”);
var xml=$.parseXML(html);
div.appendChild(xml.documentElement);
div.innerHTML===html//true
您可以使用outerHTML
,它保留了原始结构:
(基于您的原始样本)
var insert=document.createElement('div');
var text=document.createTextNode('ladygaga');
插入.appendChild(文本);
document.getElementById('outer').appendChild(insert);
var e=document.getElementById('asdf')
console.log(e.outerHTML);
e、 outerHTML=e.outerHTML;
console.log(e.outerHTML);
演示:如果需要保存和恢复无效的HTML结构,可以通过XML来实现。下面的代码来自
要保存,请创建一个新的XML文档,向其中添加要序列化的节点:
var asdf = document.getElementById("asdf");
var outer = document.getElementById("outer");
var add = document.getElementById("add");
var save = document.getElementById("save");
var restore = document.getElementById("restore");
var saved = undefined;
save.addEventListener("click", function () {
if (saved !== undefined)
return; /// Do not overwrite
// Create a fake document with a single top-level element, as
// required by XML.
var parser = new DOMParser();
var doc = parser.parseFromString("<top/>", "text/xml");
// We could skip the cloning and just move the nodes to the XML
// document. This would have the effect of saving and removing
// at the same time but I wanted to show what saving while
// preserving the data would look like
var clone = asdf.cloneNode(true);
var top = doc.firstChild;
var child = asdf.firstChild;
while (child) {
top.appendChild(child);
child = asdf.firstChild;
}
saved = top.innerHTML;
console.log("saved as: ", saved);
// Perform the removal here.
asdf.innerHTML = "";
});
var asdf=document.getElementById(“asdf”);
var outer=document.getElementById(“outer”);
var add=document.getElementById(“add”);
var save=document.getElementById(“保存”);
var restore=document.getElementById(“restore”);
var保存=未定义;
save.addEventListener(“单击”),函数(){
如果(已保存!==未定义)
return;///不覆盖
//使用单个顶级元素创建假文档,如下所示
//XML所要求的。
var parser=新的DOMParser();
var doc=parser.parseFromString(“,“text/xml”);
//我们可以跳过克隆,只需将节点移动到XML
//文档。这将具有保存和删除的效果
//同时,我想展示一下,在
//保存数据看起来像
var clone=asdf.cloneNode(true);
var top=doc.firstChild;
var child=asdf.firstChild;
while(儿童){
顶部。附加子对象(子对象);
child=asdf.firstChild;
}
saved=top.innerHTML;
console.log(“另存为:”,已保存);
//在此处执行删除操作。
asdf.innerHTML=“”;
});
要进行恢复,请创建一个XML文档以反序列化保存的内容,然后将节点添加到文档中:
restore.addEventListener("click", function () {
if (saved === undefined)
return; // Don't restore undefined data!
// We parse the XML we saved.
var parser = new DOMParser();
var doc = parser.parseFromString("<top>" + saved + "</top>", "text/xml");
var top = doc.firstChild;
var child = top.firstChild;
while (child) {
asdf.appendChild(child);
// Remove the extra junk added by the XML parser.
child.removeAttribute("xmlns");
child = top.firstChild;
}
saved = undefined;
console.log("inner html after restore", asdf.innerHTML);
});
restore.addEventListener(“单击”),函数(){
如果(已保存===未定义)
return;//不还原未定义的数据!
//我们解析保存的XML。
var parser=新的DOMParser();
var doc=parser.parseFromString(“+saved+”,“text/xml”);
var top=doc.firstChild;
var child=top.firstChild;
while(儿童){
asdf.儿童(儿童);
//删除XML解析器添加的额外垃圾。
儿童移除属性(“xmlns”);
child=top.firstChild;
}
保存=未定义;
log(“还原后的内部html”,asdf.innerHTML);
});
使用小提琴,您可以:
按“添加LadyGaga…”按钮创建无效的HTML
按“保存并从文档中删除”将结构保存在asdf
中并清除其内容。这会将保存的内容打印到控制台
按“还原”以还原已保存的结构
上面的代码是通用的。如果可以对要保存的HTML结构进行一些假设,则可以简化代码。例如,blah
不是一个格式良好的XML文档,因为您需要XML中的一个顶层元素。因此,上面的代码煞费苦心地添加了一个顶级元素(top
)来防止这个问题。通常也不可能仅将HTML序列化解析为XML,以便保存操作序列化为XML
这比任何东西都更能证明概念。可能有希德
function ruinTheHtml() {
var allElements = document.body.getElementsByTagName( "*" ),
next,
afterNext;
Array.prototype.map.call( allElements,function( el,i ){
if( el.tagName !== 'SCRIPT' && el.tagName !== 'STYLE' ) {
if(el.textContent === '') {
next = el.nextSibling;
afterNext = next.nextSibling;
if( afterNext.textContent === '' ) {
el.parentNode.removeChild( afterNext );
el.appendChild( next );
}
}
}
});
}
var html = "<p><div></div></p>";
var div = document.createElement("div");
var xml = $.parseXML(html);
div.appendChild(xml.documentElement);
div.innerHTML === html // true
<div id="asdf"><p id="outer"></p></div>
<script type="text/javascript">
var insert = document.createElement('div');
var text = document.createTextNode('ladygaga');
insert.appendChild(text);
document.getElementById('outer').appendChild(insert);
var e = document.getElementById('asdf')
console.log(e.outerHTML);
e.outerHTML = e.outerHTML;
console.log(e.outerHTML);
</script>
var asdf = document.getElementById("asdf");
var outer = document.getElementById("outer");
var add = document.getElementById("add");
var save = document.getElementById("save");
var restore = document.getElementById("restore");
var saved = undefined;
save.addEventListener("click", function () {
if (saved !== undefined)
return; /// Do not overwrite
// Create a fake document with a single top-level element, as
// required by XML.
var parser = new DOMParser();
var doc = parser.parseFromString("<top/>", "text/xml");
// We could skip the cloning and just move the nodes to the XML
// document. This would have the effect of saving and removing
// at the same time but I wanted to show what saving while
// preserving the data would look like
var clone = asdf.cloneNode(true);
var top = doc.firstChild;
var child = asdf.firstChild;
while (child) {
top.appendChild(child);
child = asdf.firstChild;
}
saved = top.innerHTML;
console.log("saved as: ", saved);
// Perform the removal here.
asdf.innerHTML = "";
});
restore.addEventListener("click", function () {
if (saved === undefined)
return; // Don't restore undefined data!
// We parse the XML we saved.
var parser = new DOMParser();
var doc = parser.parseFromString("<top>" + saved + "</top>", "text/xml");
var top = doc.firstChild;
var child = top.firstChild;
while (child) {
asdf.appendChild(child);
// Remove the extra junk added by the XML parser.
child.removeAttribute("xmlns");
child = top.firstChild;
}
saved = undefined;
console.log("inner html after restore", asdf.innerHTML);
});