长列表优化之滚动替换数据方案小记
最近项目中要用到比较长的列表,在浏览器中打开渲染时比较慢,并占用了较多内存,于是就同事就建议尽量减少节点,在滚动时只是替换数据,于是就决定试试这种方法。
首先要做的就是添加拖动滚动条时的事件,另外由于UE要求对滚动条进行美化,于是就选用了jscrollpane这个jQuery滚动条插件,主页是:http://jscrollpane.kelvinluck.com/
基本要求是表头固定,内容可滚动,滚动时只是替换数据,不增减节点。由于要出现滚动条,所以要添加一个空的节点来占位,所以DEMO的HTML结构如下:
<h3>DEMO</h3> <div class="bookList"> <table class="bookList_head"> <thead> <tr> <th class="book_title">Title</th> <th class="book_time">Time</th> <th class="book_author">Author</th> <th class="book_prize">Prize</th> </tr> </thead> </table> <div class="scroll-pane"> <div id="emptyContainer" class="emptyContainer"></div> <table class="bookList_body"> <tbody id="bookContent"> </tbody> </table> </div> </div>
然后要做的就是用测试数据填充列表,并给占位节点设置高度,JS代码如下:
var bookData = [], bookMap = [], bookCount = 1000, showCount = 10, bookListBodyNode = $(".bookList_body"), bookContentNode = $("#bookContent"), itemHeight = 0, oFragment = document.createDocumentFragment(); var emptyContainerNode = $("#emptyContainer"); for(var i=0;i<bookCount;i++){ bookData.push({ "title":"JavaScript高级程序设计第"+(i+1)+"版", "time":"2013-1-27", "author":"佚名"+i, "prize":(i%50+1)+".00" }); } for(i=0;i<showCount;i++){ var bookItem = $("<tr></tr>"), bookItem_title = $("<td class=\"book_title\">" + bookData[i].title + "</td>"), bookItem_time = $("<td class=\"book_time\">" + bookData[i].time + "</td>"), bookItem_author = $("<td class=\"book_author\">" + bookData[i].author + "</td>"), bookItem_prize = $("<td class=\"book_prize\">" + bookData[i].prize + "</td>"); bookItem.append(bookItem_title) .append(bookItem_time) .append(bookItem_author) .append(bookItem_prize); bookMap[i] = bookItem; oFragment.appendChild(bookItem[0]); } bookContentNode[0].appendChild(oFragment); itemHeight = parseInt(bookMap[0].height()); emptyContainerNode.css("height", bookCount * itemHeight);
下一步就是给class为scroll-pane的节点应用jScrollPane插件添加滚动条,同是要添加滚动条滚动时的事件,代码如下:
$('.scroll-pane').bind('jsp-scroll-y',function(event, scrollPositionY, isAtTop, isAtBottom){ bookListBodyNode.css("top",scrollPositionY); replaceBooklistData(scrollPositionY); } ).jScrollPane(); function replaceBooklistData(scrollPositionY){ var beginIndex = Math.round(scrollPositionY / itemHeight); for(var i=0;i<showCount;i++){ var bookItem = bookMap[i], bookItem_title = bookItem.find(".book_title"), bookItem_time = bookItem.find(".book_time"), bookItem_author = bookItem.find(".book_author"), bookItem_prize = bookItem.find(".book_prize"); bookItem_title.html(bookData[i+beginIndex].title); bookItem_time.html(bookData[i+beginIndex].time); bookItem_author.html(bookData[i+beginIndex].author); bookItem_prize.html(bookData[i+beginIndex].prize); } }
最后还要引入一个鼠标滚动时的插件mousewheel,全部代码如下:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Table Body Scroll Demo</title> <link type="text/css" href="style/jquery.jscrollpane.css" rel="stylesheet" media="all" /> <link type="text/css" href="style/demo.css" rel="stylesheet" media="all" /> <script type="text/javascript" src="script/jquery.js"></script> <script type="text/javascript" src="script/jquery.mousewheel.js"></script> <script type="text/javascript" src="script/jquery.jscrollpane.min.js"></script> </head> <body> <h3>DEMO</h3> <div class="bookList"> <table class="bookList_head"> <thead> <tr> <th class="book_title">Title</th> <th class="book_time">Time</th> <th class="book_author">Author</th> <th class="book_prize">Prize</th> </tr> </thead> </table> <div class="scroll-pane"> <div id="emptyContainer" class="emptyContainer"></div> <table class="bookList_body"> <tbody id="bookContent"> </tbody> </table> </div> </div> <script type="text/javascript" id="sourcecode"> var bookData = [], bookMap = [], bookCount = 1000, showCount = 10, bookListBodyNode = $(".bookList_body"), bookContentNode = $("#bookContent"), itemHeight = 0, oFragment = document.createDocumentFragment(); $(function(){ $('.scroll-pane').bind('jsp-scroll-y', function(event, scrollPositionY, isAtTop, isAtBottom){ bookListBodyNode.css("top",scrollPositionY); replaceBooklistData(scrollPositionY); } ).jScrollPane(); }); loadData(); function replaceBooklistData(scrollPositionY){ var beginIndex = Math.round(scrollPositionY / itemHeight); for(var i=0;i<showCount;i++){ var bookItem = bookMap[i], bookItem_title = bookItem.find(".book_title"), bookItem_time = bookItem.find(".book_time"), bookItem_author = bookItem.find(".book_author"), bookItem_prize = bookItem.find(".book_prize"); bookItem_title.html(bookData[i+beginIndex].title); bookItem_time.html(bookData[i+beginIndex].time); bookItem_author.html(bookData[i+beginIndex].author); bookItem_prize.html(bookData[i+beginIndex].prize); } } function loadData(){ var emptyContainerNode = $("#emptyContainer"); for(var i=0;i<bookCount;i++){ bookData.push({ "title":"JavaScript高级程序设计第"+(i+1)+"版", "time":"2013-1-27", "author":"佚名"+i, "prize":(i%50+1)+".00" }); } for(i=0;i<showCount;i++){ var bookItem = $("<tr></tr>"), bookItem_title = $("<td class=\"book_title\">" + bookData[i].title + "</td>"), bookItem_time = $("<td class=\"book_time\">" + bookData[i].time + "</td>"), bookItem_author = $("<td class=\"book_author\">" + bookData[i].author + "</td>"), bookItem_prize = $("<td class=\"book_prize\">" + bookData[i].prize + "</td>"); bookItem.append(bookItem_title) .append(bookItem_time) .append(bookItem_author) .append(bookItem_prize); bookMap[i] = bookItem; oFragment.appendChild(bookItem[0]); } bookContentNode[0].appendChild(oFragment); itemHeight = parseInt(bookMap[0].height()) || 34;//FOR IE7 emptyContainerNode.css("height", bookCount * itemHeight); } </script> </body> </html>
代码中的CSS(除了demo.css)和JS都可以在这里找到:https://github.com/vitch/jScrollPane
demo.css代码如下:
.bookList{ width:520px; height:364px; } .scroll-pane { height:330px; overflow: auto; } .bookList .bookList_head,.bookList .bookList_body{ width:100%; border-collapse:collapse; } .bookList .bookList_body{ z-index:999; position:absolute; top:0; left:0; } .bookList .bookList_head thead{ background-color:#F2F4F6; } .bookList th,.bookList td{ padding:8px 0px 8px 5px; text-align:left; border-bottom:1px solid #CCC; font-size:14px; } .bookList .bookList_body tr:nth-child(even){ background-color:#F0F0F0; } .bookList .bookList_body tr:hover{ background-color:#CCC; } .book_title{ width:250px; } .book_time{ width:100px; } .book_author{ width:80px; } .book_prize{ } .emptyContainer{ width:100%; z-index:-1; }
初步测试,在IE6/7/8/9、chrome、firefox下均正常显示,如果大家有更好方案,欢迎分享。