在Ajax动态加载数据的实际应用中,大家都习惯了一种思维方式:一条数据创建一行。
于是如果数量大的时候,一次性要加载完数据的话,浏览器就会卡上半天
受Flex的DataGrid控件的启发,在Flex的DataGrid控件中,展示数据的方法并不是有多少条数据就创建多少行,它最多只创建你在界面上所看到的十几二十行(假设为n行),如果数据多的话,在滚动过程中,会从数据中抽取你应该看到的这n行数据,重新展示在已经创建好的那n行控件中。
也就是说,Flex的DataGrid控件中,我们实际上看到的仅仅是那n行控件,只是它们展示的数据是根据滚动条状态来筛选出来的。
所以,如果在JS中,也用类似的方法实现,那么就是上万条数据,可能也只要创建几十个Dom而已,效率自然快得多了。
废话不多说,上代码。首先,需要一个滚动条
JS代码:
- function Scrollbar() {
- this.options = {
- total: 0, //数据总数
- pos: 0, //当前滚动位置
- itemSize: 20, //单项尺寸
- size: 200 //控件尺寸
- };
- }
- Scrollbar.prototype = (function() {
- function setOptions(options) {
- for (var attr in options) {
- this.options[attr] = options[attr];
- }
- Refresh(this);
- }
- function Refresh(_this) {
- if (!_this.created) return;
- //设置控件高度
- _this.bar.style.height = _this.options.size + "px";
- //设置内容高度
- var ch = _this.options.total * _this.options.itemSize;
- _this.content.style.height = ch + "px";
- }
- //获取滚动位置
- function getPos() {
- var top = this.bar.scrollTop;
- var pos = parseInt(top / this.options.itemSize);
- return pos;
- }
- //每页可展示的数据数量
- function getPageItems() {
- return this.options.size / this.options.itemSize;
- }
- //滚动事件响应
- function OnScroll(_this) {
- var pos = _this.getPos();
- if (pos == _this.options.pos) return;
- _this.options.pos = pos;
- _this.onScroll(pos);
- }
- //滚动条创建
- function CreateAt(dom) {
- var _this = this;
- var bar = document.createElement("div");
- var content = document.createElement("div");
- bar.appendChild(content);
- bar.style.width = "19px";
- bar.style.overflowY = "scroll";
- bar.style.overflowX = "hidden";
- if (bar.attachEvent) {
- bar.attachEvent("onscroll", function() { OnScroll(_this); });
- }
- else {//firefox兼容
- bar.addEventListener("scroll", function() { OnScroll(_this); }, false);
- }
- content.style.backgroundColor = "white";
- content.style.width = "1px";
- this.bar = bar;
- this.content = content;
- if (typeof (dom) == "string") {
- dom = document.getElementById(dom);
- }
- dom.innerHTML = "";
- dom.appendChild(this.bar);
- this.created = true;
- Refresh(this);
- }
- return {
- setOptions: setOptions,
- CreateAt: CreateAt,
- getPos: getPos,
- getPageItems: getPageItems,
- onScroll: null //模拟滚动条事件
- };
- })();
HTML页面代码
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <title>表格控件</title>
- <script src="Scrollbar.js" type="text/javascript"></script>
- <script language="javascript" type="text/javascript">
- var data = [];
- //创建一万条示例数据
- for (var i = 0; i < 10000; i++) {
- var row = { id: i, text: "text" + i };
- data.push(row);
- }
- //创建滚动条
- var scrbar = new Scrollbar();
- window.onload = function() {
- scrbar.CreateAt("divScroll");
- scrbar.setOptions({ total: 10000,size:300 });
- scrbar.onScroll = function(pos) {
- ShowData(pos);
- }
- //获取模板
- var items = scrbar.getPageItems();
- var tpl = document.getElementById("trTpl");
- tpl.parentNode.removeChild(tpl);
- //仅创建所看到的几十行表格,所以自然快得多
- var list = document.getElementById("tblList");
- for (var i = 0; i < data.length && i < items; i++) {
- var nr = tpl.cloneNode(true); //从模板行复制新行
- list.appendChild(nr);
- }
- ShowData(scrbar.getPos());
- }
- //根据滚动条,展示数据
- function ShowData(pos) {
- var n=scrbar.getPageItems();
- var rows=document.getElementById("tblList").rows;
- for (var i = 0; i < n; i++) {
- var row = rows[i];
- var item = data[i + pos];
- row.cells["tdID"].innerHTML = item["id"];
- row.cells["tdText"].innerHTML = item["text"];
- }
- }
- </script>
- </head>
- <body>
- <div id="divScroll" style="float:right">
- </div>
- <table border="1">
- <!--行标题-->
- <thead><tr>
- <th>ID</th>
- <th>Text</th>
- </tr></thead>
- <!--数据展示区-->
- <tbody id="tblList"><tr id="trTpl">
- <td id="tdID"> </td>
- <td id="tdText"> </td>
- </tr></tbody>
- </table>
- </body>
- </html>
OK!上万条数据,也是瞬间的事
当然,页面很粗糙,不过加点JS代码把那个滚动条和表格对齐一下,也就差不多了。
代码还没封装好,以后再慢慢封装了
而且,还轻易地解决了一个常见问题:固定表格的标题行,哈哈。。。。