一、概述
在本文中将讨论如何实现一个基于Ajax的可滚动的表格,在这个表格中,每一行都是从服务器动态获得的,当用户滚动时,整个页并不刷新,而只是局部刷新。这项技术对于实现拥有很多动态数据的表格页是非常有效和便利的。例如,当重表调整页的尺寸后,表格数据将会平滑地滚动。这是由于表格中的数据是通过AJAX从服务端异步获得的,然后由JavaScript对数据进行分析,并动态地插入每一行,而XMLHttpRequest对象用于向服务端发送请求,最后由CSS控制显示风格。
动态滚动表格的实现主要得意于现代的浏览器引入了XMLHttpRequest对象。这使得JavaScript对象可以使用异步的方式向服务端发送请求,并从服务端接收响应,而这一切都不需要刷新整个网页。更在很多的Web2.0站点都使用了很多AJAX技术来使界面变得更丰富多彩,其中XMLHttpRequest在这些站点和这些动态的网页中被广泛地使用。
在本文中将讨论如何实现一个基于Ajax的可滚动的表格,在这个表格中,每一行都是从服务器动态获得的,当用户滚动时,整个页并不刷新,而只是局部刷新。这项技术对于实现拥有很多动态数据的表格页是非常有效和便利的。例如,当重表调整页的尺寸后,表格数据将会平滑地滚动。这是由于表格中的数据是通过AJAX从服务端异步获得的,然后由JavaScript对数据进行分析,并动态地插入每一行,而XMLHttpRequest对象用于向服务端发送请求,最后由CSS控制显示风格。
动态滚动表格的实现主要得意于现代的浏览器引入了XMLHttpRequest对象。这使得JavaScript对象可以使用异步的方式向服务端发送请求,并从服务端接收响应,而这一切都不需要刷新整个网页。更在很多的Web2.0站点都使用了很多AJAX技术来使界面变得更丰富多彩,其中XMLHttpRequest在这些站点和这些动态的网页中被广泛地使用。
可滚动的表单是一个非常好的富客户端接口,它使用了Web2.0的技术来为用户展现Web内容。动态滚动技术的实现从某种程度上也取决于最新的CSS2标准的推出,这个新的CSS标准现在已经被很多流行的浏览器支持。在本文提供的代码中,我将介绍如何在屏幕的一部分实现可动态滚动的表格,但如果读者所使用的浏览器不动态最新的CSS标准,而只动态AJAX,这个动态表格将变成充满整个页面,而不是屏幕的一部分。
图1是一个Google读者网站的一个动态表格的例子。要注意的是在图1的截屏上一100项记录,通过移动垂直滚动条可看以更多的记录,当显示到140条时(如图2所示),滚动条的大小开始变化 。这时,所有其他的记录仍然保持在本页的同样的位置。
图1 一个显示100条记录的动态滚动表单
图2 在表单后又新加了40条记录,注意滚动条的位置
图1是一个Google读者网站的一个动态表格的例子。要注意的是在图1的截屏上一100项记录,通过移动垂直滚动条可看以更多的记录,当显示到140条时(如图2所示),滚动条的大小开始变化 。这时,所有其他的记录仍然保持在本页的同样的位置。
图1 一个显示100条记录的动态滚动表单
图2 在表单后又新加了40条记录,注意滚动条的位置
1
二、如保实现动态表单
为了使任何HTML元素(在本文中是表格)可滚动,需要使用一个可滚动的区域,在这里是DIV,这个元素应该比表格的实际高度小。如一个DIV的高度为100px,包含一个高度为200px的表格,这样才可以使表格滚动。下面的代码演示了div和table的使用:
<div style="height:100px; width:50px;
overflow:auto; overflow-x:hidden;">
<table style="height:200px;">
<tr><td>vlad</td></tr>
</table>
</div>
图3 产生滚动行为的例子代码
要注意的是,如果我们将table和div分开写,那么就只有div滚动,而不是表在滚动。让我们先看看如下的代码:
要注意的是,如果我们将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>
<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>
图4
我们注意到table的高度是50,但它仍然不滚动。
上面代码的两个CSS属性:overflow auto和overflow-x:hidden,实际上是将滚动条显示在div的右侧。不过浏览器的CSS引擎必须支持这两个属性,否则,这个表将不会有滚动条。
如果div中的内容落在了div的外面,可能的原因很多,如margin为负、使用了绝对位置、内容超过了width/height等等,而overflow和overflow-x属性只是描述了内容超过div的宽度应该如何去做。这些CSS属性仅仅定义了div和table的外观,而不是带有滚动属性的JavaScript API接口。为了充分理解一个动态表单的实现,我们需要知道测量HTML元素在网页中的尺寸和位置的属性。这些属性可以通过JavaScript用可编程的方式来操作,更值得庆幸的是,这些API在目前的主要浏览器中都可以使用。
三、HTML元素属性
图5 Div的属性的可视化描述
这个scrollTop属性指定了可视区域(被div的height和width定义的)的内容的上边界的位置,当用户滚动时,scrollTop将确定内容移动的距离(单位是像素)。这个scrollHeight属性指定了inner元素的实际高度(单位是像素),而clientHeight指定了可视区域的实际高度。在本文的例子中,可视区域是outer div元素,而内容是inner表。Height和Top属性并不能解决元素的border、margin或padding,如果我们的元素有这些属性的任何一个,可以使用其他类似的属性代替。和height类似,由width属性来处理水平滚动计算。
第一个被放置在页上的元素都有这些属性,以及使用这种方式的元素看起来都以来于这些属性。图6显示了一个关于div属性的简单例子。
第一个被放置在页上的元素都有这些属性,以及使用这种方式的元素看起来都以来于这些属性。图6显示了一个关于div属性的简单例子。
图6 有滚动功能 的div
四、实现动态滚动表格
为了实现一个动态表格,我现在已经将表格的显示部分放到了叫"scrolltable"的CSS中,将建立了一个id为"new_items_div"的div和一个id为"new_items"的table。叫"status"的div的目的是为了显示不同的信息。这段html代码如下:< 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 >
实现滚动逻辑的代码的第一部分是自动追加更多的行,这些行包括用户已经滚动过的行。为了实现这个功能,我建立了一个JavaScript函数detectScroll(),这个函数每0.5秒执行一次。除了这种方法,还可以为滚动事件建立一个处理事件的函数,并和div绑定。这个startPolling函数当整个页面装载时被调用,并开始周期性地调用detectScroll()函数。
在这个算法中,将探测滚动位置,并检查所滚动的距离是否大于等于可视区域高度。我还加了20个象素来将滚动条的尺寸计算在内,以确保滚动条可以在适当的位置出现。
如果用户在向下滚动后向上滚动,并没有新行出现,而只是将已经显示过的数据重新显示。下面是完整的JavaScript代码:
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 >
如果当detectScroll执行时返回true。那么会有一个新的JavaScript函数fetchAction被调用。而且还需要使用整个行数来更新div的"status"。
fetchAction函数通过异步的方式访问服务器,并使用XMLHttpRequest对象来分派一个回调函数readFeed来处理服务端的响应。我们在这里不用管服务端是如何实现的,只要知道服务端返回了一个合法的XML就可以了,服务端可以使用任何语言来完成这个任务。在本例中使用了PHP来实现服务端,读者也可以根据自己的喜好使用Java或.NET。fetchAction()函数的代码如下:
function fetchAction(si) { var xmlHttp = getXmlHttpObject(); if (xmlHttp == null ) { alert('警告,浏览器不支持XmlHttpObject()'); return ; } xmlHttp.onreadystatechange = function (){ if (xmlHttp.readyState == 4 || xmlHttp.readyState == " complete " ){ readFeed(xmlHttp); xmlHttp = null ; } } try { url = 'fetch_items.php ? ri = ' + (Math.floor(Math.random() * 10000000 )) + ' & si = ' + si; xmlHttp.open( " GET " ,url, true ); xmlHttp.send( null ); } catch (ex){ document.getElementById( " status " ).innerHTML = ex; clearInterval(pollID); } }
1
当服务端响应XML数据时,回调函数readFeed()被调用。这个函数首先获得了这个XML的handle,xmlHttp.responseXML.documentElement。然后获得这个XML的所有叫"item"的元素,并用循环扫描它们,然后去处title和body。然后将body和title传递给helper函数,由addRow函数来向表中增加数据。addRow方法可以获得table对象,在最后插入一个新行,并插入title和body HTML。下面是readFeed
函数的实现:
五、动态分析和插入数据
下面我们来对服务端返回的XML数据进行分析和动态地向table中插入数据行,下面是返回的XML
的代码:<?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函数的实现的源代码:
function addRow(table_id, dtitle, dbody){ pTable = document.getElementById(table_id); row1 = pTable.insertRow(pTable.rows.length); cell1 = row1.insertCell(0 ); cell1.innerHTML = dtitle; cell2 = row1.insertCell(1 ); cell2.innerHTML = dbody; }
在本文的例子页中,一开始有10行,当用户向下滚动时,就会显示超过10行的数据。最终结果如下图所示:
六、结论
在本文中,为读者展现了一个基于Ajax的动态滚动表的实现。这个滚动表可以用异步的方式从服务端获取数据,并无刷新地加到表格中。这一切都是由JavaScript实现。这种实现方式的好处是将已经显示过的数据都保存在客户端,这样减小了数据在网络之间的传输。读者可以将这种技术加到自己的系统中,以实现更丰富的Web界面。