Firefox outerHTML实现代码


Posted in Javascript onJune 04, 2009

减少DOM数可以加快浏览器的在解析页面过程中DOM Tree和render tree的构建,从而提高页面性能。为此我们可以把页面中那些首屏渲染不可见的部分HTML暂存在TextArea中,等完成渲染后再处理这部分HTML来达到这个目的。 要把TextArea 中暂存的HTML内容添加到页面中,使用元素的outerHTML属性是最简单方便的了,不过在DOM标准中并没有定义outerHTML,支持的浏览器有IE6+,safari, operal和 Chrome,经测试FF4.0- 中还不支持。所以我们就来实现一个可以跨浏览器的outerHTML。
outerHTML 就是获取或设置包含元素标签本身在内的html。下面是实现代码:

if(typeof HTMLElement !== "undefined" && !("outerHTML" in HTMLElement.prototype)) { 
//console.log("defined outerHTML"); 
HTMLElement.prototype.__defineSetter__("outerHTML",function(str){ 
var fragment = document.createDocumentFragment(); 
var div = document.createElement("div"); 
div.innerHTML = str; 
for(var i=0, n = div.childNodes.length; i<n; i++){ 
fragment.appendChild(div.childNodes[i]); 
} 
this.parentNode.replaceChild(fragment, this); 
}); 
// 
HTMLElement.prototype.__defineGetter__("outerHTML",function(){ 
var tag = this.tagName; 
var attributes = this.attributes; 
var attr = []; 
//for(var name in attributes){//遍历原型链上成员 
for(var i=0,n = attributes.length; i<n; i++){//n指定的属性个数 
if(attributes[i].specified){ 
attr.push(attributes[i].name + '="' + attributes[i].value + '"'); 
} 
} 
return ((!!this.innerHTML) ? 
'<' + tag + ' ' + attr.join(' ')+'>'+this.innerHTML+'</'+tag+'>' : 
'<' + tag + ' ' +attr.join(' ')+'/>'); 
}); 
}

代码说明:
1 代码中首先条件判断来监测浏览器是否支持outerHTML以避免覆盖浏览器原生的实现。
2 "__defineSetter__","__defineGetter__" 是firefox浏览器私有方面。分别定义当设置属性值和获取属性要执行的操作。
3 在"__defineSetter__" "outerHTML"中为了避免插入页面中元素过多导致频繁发生reflow影响性能。使用了文档碎片对象fragment来暂存需要插入页面中DOM元素。
4 在"__defineGetter__" "outerHTML" 中使用元素attributes属性来遍历给元素指定的属性。结合innerHTML返回了包含原属本身在内的html字符串。
测试代码:
<!DOCTYPE html> 
<html> 
<head> 
<meta charset="utf-8" /> 
<title>outerHTML</title> 
</head> 
<body> 
<div id="content" class="test"> 
<p>This is <strong>paragraph</strong> with a list following it</p> 
<ul> 
<li>Item 1</li> 
<li>Item 2</li> 
<li>Item 3</li> 
<li>Item 4</li> 
</ul> 
</div> 
<script> 
if(typeof HTMLElement !== "undefined" && !("outerHTML" in HTMLElement.prototype)) { 
console.log("defined outerHTML"); 
HTMLElement.prototype.__defineSetter__("outerHTML",function(str){ 
var fragment = document.createDocumentFragment(); 
var div = document.createElement("div"); 
div.innerHTML = str; 
for(var i=0, n = div.childNodes.length; i<n; i++){ 
fragment.appendChild(div.childNodes[i]); 
} 
this.parentNode.replaceChild(fragment, this); 
}); 
// 
HTMLElement.prototype.__defineGetter__("outerHTML",function(){ 
var tag = this.tagName; 
var attributes = this.attributes; 
var attr = []; 
//for(var name in attributes){//遍历原型链上成员 
for(var i=0,n = attributes.length; i<n; i++){//n指定的属性个数 
if(attributes[i].specified){ 
attr.push(attributes[i].name + '="' + attributes[i].value + '"'); 
} 
} 
return ((!!this.innerHTML) ? 
'<' + tag + ' ' + attr.join(' ')+'>'+this.innerHTML+'</'+tag+'>' : 
'<' + tag + ' ' +attr.join(' ')+'/>'); 
}); 
} 
var content = document.getElementById("content"); 
alert(content.outerHTML) 
</script> 
</body> 
</html>

假设要获取 <p id="outerID">sdfdsdfsd</p> 的 P的outerHTML
代码:
var _p = document.getElementById('outerID'); 
_P = _P.cloneNode(); 
var _DIV = document.createElement(); 
_DIV.appendChild(_P); 
alert(_DIV.innerHTML); 就是P的outerHTML;

firefox没有outerHTML用以下方法解决
/** 
* 兼容firefox的 outerHTML 使用以下代码后,firefox可以使用element.outerHTML 
**/ 
if(window.HTMLElement) { 
HTMLElement.prototype.__defineSetter__("outerHTML",function(sHTML){ 
var r=this.ownerDocument.createRange(); 
r.setStartBefore(this); 
var df=r.createContextualFragment(sHTML); 
this.parentNode.replaceChild(df,this); 
return sHTML; 
}); 
HTMLElement.prototype.__defineGetter__("outerHTML",function(){ 
var attr; 
var attrs=this.attributes; 
var str="<"+this.tagName.toLowerCase(); 
for(var i=0;i<attrs.length;i++){ 
attr=attrs[i]; 
if(attr.specified) 
str+=" "+attr.name+'="'+attr.value+'"'; 
} 
if(!this.canHaveChildren) 
return str+">"; 
return str+">"+this.innerHTML+"</"+this.tagName.toLowerCase()+">"; 
}); 
HTMLElement.prototype.__defineGetter__("canHaveChildren",function(){ 
switch(this.tagName.toLowerCase()){ 
case "area": 
case "base": 
case "basefont": 
case "col": 
case "frame": 
case "hr": 
case "img": 
case "br": 
case "input": 
case "isindex": 
case "link": 
case "meta": 
case "param": 
return false; 
} 
return true; 
}); 
}

测试有效.
关于insertAdjacentHTML兼容的解新决办法
//---在组件最后插入html代码 
function InsertHtm(op,code,isStart){ 
if(Dvbbs_IsIE5) 
op.insertAdjacentHTML(isStart ? "afterbegin" : "afterEnd",code); 
else{ 
var range=op.ownerDocument.createRange(); 
range.setStartBefore(op); 
var fragment = range.createContextualFragment(code); 
if(isStart) 
op.insertBefore(fragment,op.firstChild); 
else 
op.appendChild(fragment); 
} 
}

关于inner/outerHTML在NC6中的参考
DOM level 1 has no methods to allow for insertion of unparsed HTML into the document tree (as IE allows with insertAdjacentHTML or assignment to inner/outerHTML).NN6 (currently in beta as NN6PR3) know supports the .innerHTMLproperty of HTMLElements so that you can read or write the innerHTML of a page element like in IE4+.NN6 also provides a DOM level 2 compliant Range object to which a createContextualFragment('html source string')was added to spare DOM scripters the task of parsing html and creating DOM elements.You create a Range with var range = document.createRange();Then you should set its start point to the element where you want to insert the html for instance var someElement = document.getElementById('elementID'); range.setStartAfter(someElement);Then you create a document fragment from the html source to insert for example var docFrag = range.createContextualFragment('<P>Kibology for all.</P>');and insert it with DOM methods someElement.appendChild(docFrag);The Netscape JavaScript 1.5 version even provides so called setters for properties which together with the ability to prototype the DOM elements allows to emulate setting of outerHMTL for NN6:<SCRIPT LANGUAGE="JavaScript1.5">if (navigator.appName == 'Netscape') { HTMLElement.prototype.outerHTML setter = function (html) { this.outerHTMLInput = html; var range = this.ownerDocument.createRange(); range.setStartBefore(this); var docFrag = range.createContextualFragment(html); this.parentNode.replaceChild(docFrag, this); }}</SCRIPT> If you insert that script block you can then write cross browser code assigning to .innerHTML .outerHTMLfor instance document.body.innerHTML = '<P>Scriptology for all</P>';which works with both IE4/5 and NN6.The following provides getter functions for .outerHTMLto allow to read those properties in NN6 in a IE4/5 compatible way. Note that while the scheme of traversing the document tree should point you in the right direction the code example might not satisfy your needs as there are subtle difficulties when trying to reproduce the html source from the document tree. See for yourself whether you like the result and improve it as needed to cover other exceptions than those handled (for the empty elements and the textarea element).<HTML><HEAD><STYLE></STYLE><SCRIPT LANGUAGE="JavaScript1.5">var emptyElements = { HR: true, BR: true, IMG: true, INPUT: true};var specialElements = { TEXTAREA: true};HTMLElement.prototype.outerHTML getter = function () { return getOuterHTML (this);}function getOuterHTML (node) { var html = ''; switch (node.nodeType) { case Node.ELEMENT_NODE: html += '<'; html += node.nodeName; if (!specialElements[node.nodeName]) { for (var a = 0; a < node.attributes.length; a++) html += ' ' + node.attributes[a].nodeName.toUpperCase() + '="' + node.attributes[a].nodeValue + '"'; html += '>'; if (!emptyElements[node.nodeName]) { html += node.innerHTML; html += '<\/' + node.nodeName + '>'; } } else switch (node.nodeName) { case 'TEXTAREA': for (var a = 0; a < node.attributes.length; a++) if (node.attributes[a].nodeName.toLowerCase() != 'value') html += ' ' + node.attributes[a].nodeName.toUpperCase() + '="' + node.attributes[a].nodeValue + '"'; else var content = node.attributes[a].nodeValue; html += '>'; html += content; html += '<\/' + node.nodeName + '>'; break; } break; case Node.TEXT_NODE: html += node.nodeValue; break; case Node.COMMENT_NODE: html += '<!' + '--' + node.nodeValue + '--' + '>'; break; } return html;}</SCRIPT></HEAD><BODY><A HREF="javascript: alert(document.documentElement.outerHTML); void 0">show document.documentElement.outerHTML</A>|<A HREF="javascript: alert(document.body.outerHTML); void 0">show document.body.outerHTML</A>|<A HREF="javascript: alert(document.documentElement.innerHTML); void 0">show document.documentElement.innerHTML</A>|<A HREF="javascript: alert(document.body.innerHTML); void 0">show document.body.innerHTML</A><FORM NAME="formName"><TEXTAREA NAME="aTextArea" ROWS="5" COLS="20">JavaScript.FAQTs.comKibology for all.</TEXTAREA></FORM><DIV><P>JavaScript.FAQTs.com</P><BLOCKQUOTE>Kibology for all.<BR>All for Kibology.</BLOCKQUOTE></DIV></BODY></HTML>Note that the getter/setter feature is experimental and its syntax is subject to change.
HTMLElement.prototype.innerHTML setter = function (str) { var r = this.ownerDocument.createRange(); r.selectNodeContents(this); r.deleteContents(); var df = r.createContextualFragment(str); this.appendChild(df); return str;}HTMLElement.prototype.outerHTML setter = function (str) { var r = this.ownerDocument.createRange(); r.setStartBefore(this); var df = r.createContextualFragment(str); this.parentNode.replaceChild(df, this); return str;}
HTMLElement.prototype.innerHTML getter = function () { return getInnerHTML(this);}
function getInnerHTML(node) { var str = ""; for (var i=0; i<node.childNodes.length; i++) str += getOuterHTML(node.childNodes.item(i)); return str;}
HTMLElement.prototype.outerHTML getter = function () { return getOuterHTML(this)}
function getOuterHTML(node) { var str = ""; switch (node.nodeType) { case 1: // ELEMENT_NODE str += "<" + node.nodeName; for (var i=0; i<node.attributes.length; i++) { if (node.attributes.item(i).nodeValue != null) { str += " " str += node.attributes.item(i).nodeName; str += "=\""; str += node.attributes.item(i).nodeValue; str += "\""; } }
if (node.childNodes.length == 0 && leafElems[node.nodeName]) str += ">"; else { str += ">"; str += getInnerHTML(node); str += "<" + node.nodeName + ">" } break; case 3: //TEXT_NODE str += node.nodeValue; break; case 4: // CDATA_SECTION_NODE str += "<![CDATA[" + node.nodeValue + "]]>"; break; case 5: // ENTITY_REFERENCE_NODE str += "&" + node.nodeName + ";" break;
case 8: // COMMENT_NODE str += "<!--" + node.nodeValue + "-->" break; }
return str;}
var _leafElems = ["IMG", "HR", "BR", "INPUT"];var leafElems = {};for (var i=0; i<_leafElems.length; i++) leafElems[_leafElems[i]] = true;
然后我们可以封成JS引用
if (/Mozilla\/5\.0/.test(navigator.userAgent)) document.write('<script type="text/javascript" src="mozInnerHTML.js"></sc' + 'ript>');
<script language="JavaScript" type="Text/JavaScript"> 
<!-- 
var emptyElements = { HR: true, BR: true, IMG: true, INPUT: true }; var specialElements = { TEXTAREA: true }; 
HTMLElement.prototype.outerHTML getter = function() { 
return getOuterHTML(this); 
} 
function getOuterHTML(node) { 
var html = ''; 
switch (node.nodeType) { 
case Node.ELEMENT_NODE: html += '<'; html += node.nodeName; if (!specialElements[node.nodeName]) { 
for (var a = 0; a < node.attributes.length; a++) 
html += ' ' + node.attributes[a].nodeName.toUpperCase() + '="' + node.attributes[a].nodeValue + '"'; 
html += '>'; 
if (!emptyElements[node.nodeName]) { 
html += node.innerHTML; 
html += '<\/' + node.nodeName + '>'; 
} 
} else 
switch (node.nodeName) { 
case 'TEXTAREA': for (var a = 0; a < node.attributes.length; a++) 
if (node.attributes[a].nodeName.toLowerCase() != 'value') 
html 
+= ' ' + node.attributes[a].nodeName.toUpperCase() + '="' + node.attributes[a].nodeValue 
+ '"'; 
else 
var content = node.attributes[a].nodeValue; 
html += '>'; html += content; html += '<\/' + node.nodeName + '>'; break; 
} break; 
case Node.TEXT_NODE: html += node.nodeValue; break; 
case Node.COMMENT_NODE: html += '<!' + '--' + node.nodeValue + '--' + '>'; break; 
} 
return html; 
} 
//--> 
</script>
Javascript 相关文章推荐
从父页面读取和操作iframe中内容方法
Jul 25 Javascript
js 金额格式化来回转换示例
Feb 23 Javascript
js加密解密字符串可自定义密码因子
May 13 Javascript
node.js中的querystring.parse方法使用说明
Dec 10 Javascript
浅谈js 闭包引起的内存泄露问题
Jun 22 Javascript
jQuery实现简单隔行变色的方法
Feb 20 Javascript
原生js实现返回顶部缓冲效果
Jan 18 Javascript
JS实现汉字与Unicode码相互转换的方法详解
Apr 28 Javascript
JavaScript中最常用的10种代码简写技巧总结
Jun 28 Javascript
薪资那么高的Web前端必看书单
Oct 13 Javascript
React Native基础入门之初步使用Flexbox布局
Jul 02 Javascript
Vue和Flask通信的实现
May 19 Vue.js
IE innerHTML,outerHTML所引起的问题
Jun 04 #Javascript
js 鼠标点击事件及其它捕获
Jun 04 #Javascript
一些常用的JS功能函数(2009-06-04更新)
Jun 04 #Javascript
javascript globalStorage类代码
Jun 04 #Javascript
IE8 兼容性问题(属性名区分大小写)
Jun 04 #Javascript
JavaScript效率调优经验
Jun 04 #Javascript
cookie丢失问题(认证失效) Authentication (用户验证信息)也会丢失
Jun 04 #Javascript
You might like
windows下PHP APACHE MYSQ完整配置
2007/01/02 PHP
php实现自动获取生成文章主题关键词功能的深入分析
2013/06/03 PHP
php获取操作系统语言代码
2013/11/04 PHP
php 利用socket发送HTTP请求(GET,POST)
2015/08/24 PHP
jQuery+PHP发布的内容进行无刷新分页(Fckeditor)
2015/10/22 PHP
在IE,Firefox,Safari,Chrome,Opera浏览器上调试javascript
2008/12/02 Javascript
使用IE6看老赵的博客 jQuery初探
2010/01/17 Javascript
JS实现的用来对比两个用指定分隔符分割的字符串是否相同
2014/09/19 Javascript
清除浏览器缓存的几种方法总结(必看)
2016/12/09 Javascript
js 原型对象和原型链理解
2017/02/09 Javascript
Angularjs中的验证input输入框只能输入数字和小数点的写法(推荐)
2017/08/16 Javascript
JavaScript 中判断变量是否为数字的示例代码
2020/10/22 Javascript
python编程开发之类型转换convert实例分析
2015/11/13 Python
用pickle存储Python的原生对象方法
2017/04/28 Python
Python set常用操作函数集锦
2017/11/15 Python
TensorFlow模型保存和提取的方法
2018/03/08 Python
对Pandas MultiIndex(多重索引)详解
2018/11/16 Python
Python检查ping终端的方法
2019/01/26 Python
python中enumerate() 与zip()函数的使用比较实例分析
2019/09/03 Python
python中的逆序遍历实例
2019/12/25 Python
jupyter notebook tensorflow打印device信息实例
2020/04/20 Python
vscode配置anaconda3的方法步骤
2020/08/08 Python
python邮件中附加文字、html、图片、附件实现方法
2021/01/04 Python
HTML5+CSS3实例 :canvas 模拟实现电子彩票刮刮乐代码
2016/12/30 HTML / CSS
HTML5 新事件 小结
2009/07/16 HTML / CSS
全球立体声:World Wide Stereo
2018/09/29 全球购物
CLR与IL分别是什么含义
2016/08/23 面试题
医学生求职自荐信
2013/10/25 职场文书
电气工程师岗位职责
2014/01/01 职场文书
《玩具柜台前的孩子》教学反思
2014/02/13 职场文书
保险专业大学生职业规划书
2014/03/03 职场文书
社区党的群众路线教育实践活动总结材料
2014/10/31 职场文书
2015年个人剖析材料范文
2014/12/29 职场文书
家长高考寄语
2015/02/27 职场文书
公司车辆管理制度
2015/08/04 职场文书
Docker安装MySql8并远程访问的实现
2022/07/07 Servers