【IT168 专稿】
在本文中将讨论如何实现一个基于Ajax的可滚动的表格,在这个表格中,每一行都是从服务器动态获得的,当用户滚动时,整个页并不刷新,而只是局部刷新。这项技术对于实现拥有很多动态数据的表格页是非常有效和便利的。例如,当重表调整页的尺寸后,表格数据将会平滑地滚动。这是由于表格中的数据是通过AJAX从服务端异步获得的,然后由JavaScript对数据进行分析,并动态地插入每一行,而XMLHttpRequest对象用于向服务端发送请求,最后由CSS控制显示风格。
动态滚动表格的实现主要得意于现代的浏览器引入了XMLHttpRequest对象。这使得JavaScript对象可以使用异步的方式向服务端发送请求,并从服务端接收响应,而这一切都不需要刷新整个网页。更在很多的Web2.0站点都使用了很多AJAX技术来使界面变得更丰富多彩,其中XMLHttpRequest在这些站点和这些动态的网页中被广泛地使用。
图1是一个Google读者网站的一个动态表格的例子。要注意的是在图1的截屏上一100项记录,通过移动垂直滚动条可看以更多的记录,当显示到140条时(如图2所示),滚动条的大小开始变化 。这时,所有其他的记录仍然保持在本页的同样的位置。
图1 一个显示100条记录的动态滚动表单
图2 在表单后又新加了40条记录,注意滚动条的位置
要注意的是,如果我们将table和div分开写,那么就只有div滚动,而不是表在滚动。让我们先看看如下的代码:
<table style="height:50px; width:100px; overflow:auto;overflow-x:hidden;"> <tr><td><p>vlad 1</p></td></tr> <tr><td><p>vlad 2</p></td></tr> <tr><td><p>vlad 3</p></td></tr> <tr><td><p>vlad 4</p></td></tr> <tr><td><p>vlad 5</p></td></tr> </table>
图4显示了上述代码的运行结果:<hr/> <div style="height:100px; width:100px; overflow:auto;overflow-x:hidden;"> <p>Vlad 1 </p> <p>Vlad 2</p> <p>Vlad 3</p> <p>Vlad 4</p> <p>Vlad 5</p> </div>
这些CSS属性仅仅定义了div和table的外观,而不是带有滚动属性的JavaScript API接口。为了充分理解一个动态表单的实现,我们需要知道测量HTML元素在网页中的尺寸和位置的属性。这些属性可以通过JavaScript用可编程的方式来操作,更值得庆幸的是,这些API在目前的主要浏览器中都可以使用。
第一个被放置在页上的元素都有这些属性,以及使用这种方式的元素看起来都以来于这些属性。图6显示了一个关于div属性的简单例子。
<div id='status'></div> <div id="new_items_div" style="height:500px;" class="scrolltable"> <table id="new_items" border="0" cellpadding="0" cellspacing="0" > <tbody> </tbody> </table> </div>
function startPolling(){ pollID = setInterval("detectScroll()",500); } function detectScroll(){ var intElemScrollHeightOuter = document.getElementById("new_items_div").clientHeight; var intElemScrollHeightInner = document.getElementById("new_items").scrollHeight; var intElemScrolled = document.getElementById("new_items_div").scrollTop; var height = intElemScrollHeightInner - intElemScrollHeightOuter; if (intElemScrolled >= height-20) { //alert("You are at " + document.getElementById("new_items").scrollTop + " pixels. adding rows..."); document.getElementById('status').innerHTML = "Showing <b>"+(viewCnt+5)+"</b> items"; fetchAction(viewCnt); viewCnt +=5; } return true; } fetchAction(0); startPolling(); </script>
fetchAction函数通过异步的方式访问服务器,并使用XMLHttpRequest对象来分派一个回调函数readFeed来处理服务端的响应。我们在这里不用管服务端是如何实现的,只要知道服务端返回了一个合法的XML就可以了,服务端可以使用任何语言来完成这个任务。在本例中使用了PHP来实现服务端,读者也可以根据自己的喜好使用Java或.NET。fetchAction()函数的代码如下:
当服务端响应XML数据时,回调函数readFeed()被调用。这个函数首先获得了这个XML的handle,xmlHttp.responseXML.documentElement。然后获得这个XML的所有叫"item"的元素,并用循环扫描它们,然后去处title和body。然后将body和title传递给helper函数,由addRow函数来向表中增加数据。addRow方法可以获得table对象,在最后插入一个新行,并插入title和body HTML。下面是readFeed函数的实现:<?xml version='1.0' encoding='ISO-8859-1'?> <channel> <item> <title>Vlad</title> <body><![CDATA[some text]]></body> </item> </channel>
function readFeed(xmlHttp) { try { if (xmlHttp.responseText.indexOf('invalid') == -1) { var node = xmlHttp.responseXML.documentElement; var items = node.getElementsByTagName('item'); if (items.length == 0){ // hmm still 0 - something is wrong with the stream document.getElementById("status").innerHTML = "nothing was returned..."; } for (var n=0; n < items.length; n++) { var itemTitle = items[n].getElementsByTagName('title').item(0).firstChild.data; var itemBody = items[n].getElementsByTagName('body').item(0).firstChild.data; addRow("new_items",itemTitle, itemBody); } } } catch (e) { document.getElementById("status").innerHTML = e; } }
下面是addRow函数的实现的源代码:
在本文的例子页中,一开始有10行,当用户向下滚动时,就会显示超过10行的数据。最终结果如下图所示: