最近,一位IT同事询问我如何使用JavaScript的方式来创建一个具备排序能力的文件夹/文件的层级浏览视图。他希望这个视图看上去和以下的样式相似:
项目1
项目2
项目3
文件夹1
项目1
项目2
项目4
文件夹2
项目1
项目2
项目5
…
使用XML数据绑定的表格
我建议的方法是使用绑定到XML的嵌套表格,这种解决方案很简单,我可以使用DOM方法来安排涉及到的XML,而表格将反映这些改变。(注意:这种解决方案是设计用于Internet Explorer 5.0及以上版本的,IE具有与表格的数据绑定功能,而其它的浏览器没有同样的功能。)在此处可使用样本对浏览器进行检测。
如果您以前曾在IE中使用过XML数据绑定表格,您一定知道XML的格式的重要性,在根元素下的每一个子节点都代表了表格中的一行,嵌套表格可以绑定到行节点内的嵌套节点等等。列表A包含了这种绑定的一个梗概示例。
列表A
<xml id="xmlMain">
<root>
<row>
<item1/>
<item2/>
<row>
<item1/>
<item2/>
</row>
</row>
</root>
</xml>
<table dataSrc="#xmlMain">
<tbody>
<tr>
<td><span dataFld="item1"></span></td>
</tr>
<tr>
<td>
<table dataSrc="#xmlMain" dataFld="row">
<tbody>
<tr>
<td><span dataFld="item2"></span></td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
在XML数据岛xmlMain中,行是由位于第一层级中的行节点表示的,单独的字段是由项目节点表示的,在表格HTML中,您可以通过指定TABLE元素的dataSrc属性来创建一个绑定,该数值使用磅的符号(#)和XML数据岛的标识符属性来表示。行的数量反映在XML文件行节点的数量上,数据项目绑定在表格节点的行节点上,这意味着,如果一个TR在父节点包含了绑定到字段的元素,那么该行将成为在XML文件中该层级绑定到重复节点的数量。
在这个例子中,第一行只显示了一次,因为在XML中根元素下只有一个行节点,然而,另一个TR元素是专门指定到表格的,该行包含了一个嵌套的表格,该表格中的行将绑定到XML中的嵌套行节点,这个表格和父表格唯一的区别在于TABLE定义中dataFld属性的不同。
装入XML数据和绑定表格
现在我们基本知道了XML数据是如何展示的,我们还需要加入排序的功能,既然表格HTML已经绑定到XML了,我们就不用担心它了,表格将反映任何XML的改变,一个需要注意的重要细节是每一个被绑定的行都拥有nodeName行。
您不应让客户端的电脑对大量数据进行排序,这个任务应该留给原始数据提供者,比如SQL服务器,然而,对于小规模的、当场进行的排序,一个JavaScript的解决方案就很好了。
使用DOM方法来实现排序是一件轻而易举的事情了,所有的行就是您需要排序的单独项目,每一行都应包含一个当作排序标准的字段,在我的例子中,我使用了一个日期字段。
首先,创建一个没有改变的节点数组来代表您需要排序的节点,为了实现这一点,使用父节点的selectNodes方法来选择您需要排序的节点,对于外部排序而言,父节点应当是XML的根元素。(您可以通过行节点的名字来识别这些节点。)而且,我提到了“外部排序”,这意味着我们需要对嵌套行节点排序的能力,所以我们应该构建一个递归函数来对内部的行进行排序就像对外部的行排序一样,这个函数将接收一个父节点和排序标准的字段名称。
最后,这是排序的算法,根据选定的节点数组,每个数组的行节点与行节点在父节点的选择标准元素相匹配;跳过每个叠代后的行节点就可知道当前数组的行节点的选择标准不超过被叠代的选择标准元素的数值。在此,数组的当前行节点在被叠代的行节点使用insertBefore的DOM方法前被插入到数组中,使用数组来控制节点参考的原因是任何对DOM的改变都将反映在由selectNodes方法返回的数组的顺序上,在这个数组中,节点的顺序不会改变因为我们对这些节点进行了叠代。
列表B包含了排序函数,代码很灵活,这个算法的最大限制因素在于行节点必需是命名过的行,您可以通过将选择标准设为元素名称的数组来自行添加排序条件,从而增强功能。您可以在选择标准中连接节点的值,添加数字来执行大于的条件,这也可以用于对文件夹中的文件排序,只需要给定它们排序的数值即可(也就是,文件夹设为1,文件设为2)。
列表B
<script language="JavaScript">
function sort(sortNode, sortOn)
{
var nodes = sortNode.selectNodes("row");
for (vari = 0; i < nodes.length; i++)
{
var node = nodes[i];
var rows = node.selectNodes("row");
for (var n = 0; n < rows.length; n++)
sort(node, sortOn);
var tests = node.parentNode.selectNodes("row");
for (varnd = 0; nd < tests.length; nd++)
{
var test = tests[nd];
if (test.selectSingleNode(sortOn).text > node.selectSingleNode(sortOn).text)
{
test.parentNode.insertBefore(node, test);
break;
}
}
}
}
</script>