javascript 异步的innerHTML使用分析

  作者:bea

当然,这个分时加载技术只是一个辅助技术,本身没有添加节点的能力。如今,另一种更奇特的技术Asynchronous innerHTML又被开发出来了,不能不赞一下外国人在这方面研究是非常超前的。 代码如下: function asyncInnerHTML(HTML, callback) { var temp = document.createElement('div'), frag = document.createDocumentFragment(); temp.
当然,这个分时加载技术只是一个辅助技术,本身没有添加节点的能力。如今,另一种更奇特的技术
Asynchronous innerHTML又被开发出来了,不能不赞一下外国人在这方面研究是非常超前的。


代码如下:


function asyncInnerHTML(HTML, callback) {
var temp = document.createElement('div'),
frag = document.createDocumentFragment();
temp.innerHTML = HTML;//要加入的内容先放到这里。
(function(){
if(temp.firstChild) {
frag.appendChild(temp.firstChild);//然后一点点挪到文档碎片
setTimeout(arguments.callee, 0);//利用异步调用自身拼凑文档碎片,直到div的节点被搬空
} else {
callback(frag);//这里才是真正执行插入节点的操作
}
})();
}


此技术的优点:
1. 利用闭包解决 IE6 的内存溢出问题
2. 利用setTimeout(fn,0) 这个hack将操作从队列中拖出,防止浏览器假死
3. 利用Document Fragment减少对页面的渲染次数
4. 回调的节点可以使用 DOM 标准的手法(appendChild)插入(如IE的table,tbody,tr,td等标签的innerHTML是只读的)
使用方法:


代码如下:


var htmlStr = '<div><p>...</p><p>...</p><div><div>...</div>';
asyncInnerHTML(htmlStr, function(fragment){
// You can treat 'fragment' as a regular node.
document.body.appendChild(fragment);
});


不过,这个方法在table中添加节点时并不是个个浏览器都行得通,不得不说是一大败笔。经测试IE8,IE6,FF3.5渲染出现差错,chrome,safari4,opera10等能完好地把表格渲染出来。估计是IE8等在把节点转移到文档碎片时发生节点丢失现象。



<style>
.filament_table {
border-collapse:collapse !important;
border-top:1px solid #A9EA00;
border-left:1px solid #C1DAD7;
table-layout:fixed;
width:400px;
}
.filament_table thead th {
background:#A9EA00;
color:#FCDE6A;
border-bottom:1px solid #C1DAD7;
border-right:1px solid #C1DAD7;
padding:2px 5px;
}
.filament_table tbody td,.filament_table tbody th {
border-bottom:1px solid #C1DAD7;
border-right:1px solid #C1DAD7;
padding:2px 5px;
color:#76C2C3;
}
.filament_table tfoot td {
border-bottom:1px solid #C1DAD7;
border-right:1px solid #C1DAD7;
background:#A9EA00;
color:#FCDE6A;
font-size:12px;
padding:0;
}
.filament_table tbody td a{
text-decoration:none;
color:#76C2C3;
}
.filament_table tbody tr:nth-child(even) {
background:#F7FBFF;
}
</style>
<script type="text/javascript">
var getData = function(){
var builder = [];
for(var i=0;i<10;i++){
builder.push("<tr><td>目录");
builder.push(i);
builder.push("</td><td>商品");
builder.push(i);
builder.push("</td><td>商品");
builder.push(i);
builder.push("</td></tr>");
}
return builder.join('');
}

function asyncInnerHTML(HTML, callback) {
var temp = document.createElement('div'),
frag = document.createDocumentFragment();
temp.innerHTML = HTML;//要加入的内容先放到这里。
(function(){
if(temp.firstChild) {
frag.appendChild(temp.firstChild);//然后一点点挪到文档碎片
setTimeout(arguments.callee, 0);//然后把插入内容的操作作为异步调用放到一个独立的堆栈中
} else {
callback(frag);//这里才是真正执行插入节点的操作
}
})();
}
addData = function(){
asyncInnerHTML(getData(),function(flag){
var tbody = document.getElementById("test");
tbody.appendChild(flag);
})
}
</script>
<table class="filament_table">
<thead><tr><th colspan="3">异步的innerHTML</th></tr></thead>
<tbody id="test">
</tbody>
</table>
<p><button type="button" onclick="addData()">开始</button></p>




[Ctrl+A 全选 注:
如需引入外部Js需刷新才能执行]

在FF3.5的firebug显示下,table新添加的节点,标签都丢失了。


在IE8的开发人员工具中,我们发现table新添加节点出错严重,见于IE一惯的表现,这是很正常的事!


相关演示可见
无忧的贴子,发现这种方法不是最佳的插入动态内容的方法。



<style>
#myTable{height:300px;overflow:auto;border:1px solid #39F;width:600px; }
table,td,th{font-size:12px;border-collapse:collapse;height:100%;border:1px solid #39F; }
tr.odd{background:#B1E4F3; }
td.index{background:#B1E4F3;color:#000066;text-align:center; }
</style>
<body>
<div id="myTable">
<table cellspacing="0" cellpadding="2" id="tb">
<tr class="odd">
<td style="width: 51px" class="index">1</td>
<td style="width: 121px" >姓名1</td>
<td style="width: 51px"><span style="color: #00f">男</span></td>
<td style="width: 51px" >20</td>
<td style="width: 121px">1987-12-7</td>
<td style="width: 201px">这个人很懒,什么都没有留下</td>
</tr>
</table>
</div>
<script>
freeFor=function(i,to,fn){
(function(){
fn(i);
i++<to?setTimeout(arguments.callee,30):0;
})();
};
var T=document.getElementById("tb")
,R=T.rows[0]
,B=T.getElementsByTagName("tbody")[0];
freeFor(1,40,function(z){
var F = document.createDocumentFragment();
for (var i=1;i<50;++i ){
var Y=R.cloneNode(true);
var I=Y.getElementsByTagName("TD")[0];
I.innerHTML=(i*z+1);
I.className='index';
Y.className=i%2?'':'odd';
F.appendChild(Y);
};
B.appendChild(F);
F=null;
});
</script>
</body>
</html>




[Ctrl+A 全选 注:
如需引入外部Js需刷新才能执行]





有用  |  无用

猜你喜欢