标签:des style java 使用 os 数据
大家都知道EasyUI的Datagrid组件在加载大数据量时的优势并不是很明显,相对于其他一些框架,如果数据量达到几千,便会比较慢,特别是在IE下面。针对这种情况,我们首要做的是要相办法优化datagrid组件的各方面性能,不过任何事情都是可以变通解决的,virtualScrollView就是一种不错的解决方案。
virtualScrollView的准则就是尽量少画tr到table里,表格的高度是有限的,而用户的可见区域是很有限的,所以数据量很大的时候,是没有必要将所有数据数据都画到表格中,这样造成庞大的DOM,导致加载速度变慢。
源码分析
jQuery EasyUI的datagrid组件官方也扩展了一个virtualScrollView视图,我们来分析一下它的源码:
- var scrollview = $.extend({}, $.fn.datagrid.defaults.view, {
- render: function(target, container, frozen){
- var state = $.data(target, ‘datagrid‘);
- var opts = state.options;
-
-
-
- var rows = this.rows || [];
- if (!rows.length) {
- return;
- }
- var fields = $(target).datagrid(‘getColumnFields‘, frozen);
-
-
- if (frozen){
- if (!(opts.rownumbers || (opts.frozenColumns && opts.frozenColumns.length))){
- return;
- }
- }
-
- var index = this.index;
- var table = [‘<table class="datagrid-btable" cellspacing="0" cellpadding="0" border="0"><tbody>‘];
- for(var i=0; i<rows.length; i++) {
- var css = opts.rowStyler ? opts.rowStyler.call(target, index, rows[i]) : ‘‘;
- var classValue = ‘‘;
- var styleValue = ‘‘;
- if (typeof css == ‘string‘){
- styleValue = css;
- } else if (css){
- classValue = css[‘class‘] || ‘‘;
- styleValue = css[‘style‘] || ‘‘;
- }
- var cls = ‘class="datagrid-row ‘ + (index % 2 && opts.striped ? ‘datagrid-row-alt ‘ : ‘ ‘) + classValue + ‘"‘;
- var style = styleValue ? ‘style="‘ + styleValue + ‘"‘ : ‘‘;
-
-
-
-
- var rowId = state.rowIdPrefix + ‘-‘ + (frozen?1:2) + ‘-‘ + index;
- table.push(‘<tr id="‘ + rowId + ‘" datagrid-row-index="‘ + index + ‘" ‘ + cls + ‘ ‘ + style + ‘>‘);
- table.push(this.renderRow.call(this, target, fields, frozen, index, rows[i]));
- table.push(‘</tr>‘);
- index++;
- }
- table.push(‘</tbody></table>‘);
-
- $(container).html(table.join(‘‘));
- },
-
-
-
-
-
-
-
-
- onBeforeRender: function(target){
- var state = $.data(target, ‘datagrid‘);
- var opts = state.options;
- var dc = state.dc;
- var view = this;
-
- state.onLoadSuccess = opts.onLoadSuccess;
- opts.onLoadSuccess = function(){};
-
- opts.finder.getRow = function(t, p){
- var index = (typeof p == ‘object‘) ? p.attr(‘datagrid-row-index‘) : p;
- var row = $.data(t, ‘datagrid‘).data.rows[index];
- if (!row){
- var v = $(t).datagrid(‘options‘).view;
- row = v.rows[index - v.index];
- }
- return row;
- };
-
- dc.body1.add(dc.body2).empty();
- this.rows = undefined;
- this.r1 = this.r2 = [];
-
-
- dc.body2.unbind(‘.datagrid‘).bind(‘scroll.datagrid‘, function(e){
- if (state.onLoadSuccess){
- opts.onLoadSuccess = state.onLoadSuccess;
- state.onLoadSuccess = undefined;
- }
- if (view.scrollTimer){
- clearTimeout(view.scrollTimer);
- }
-
- view.scrollTimer = setTimeout(function(){
- scrolling.call(view);
- }, 50);
- });
-
- function scrolling(){
- if (dc.body2.is(‘:empty‘)){
-
- reload.call(this);
- } else {
- var firstTr = opts.finder.getTr(target, this.index, ‘body‘, 2);
- var lastTr = opts.finder.getTr(target, 0, ‘last‘, 2);
- var headerHeight = dc.view2.children(‘div.datagrid-header‘).outerHeight();
- var top = firstTr.position().top - headerHeight;
- var bottom = lastTr.position().top + lastTr.outerHeight() - headerHeight;
-
- if (top > dc.body2.height() || bottom < 0){
- reload.call(this);
- } else if (top > 0){
- var page = Math.floor(this.index/opts.pageSize);
- this.getRows.call(this, target, page, function(rows){
- this.r2 = this.r1;
- this.r1 = rows;
- this.index = (page-1)*opts.pageSize;
- this.rows = this.r1.concat(this.r2);
- this.populate.call(this, target);
- });
- } else if (bottom < dc.body2.height()){
- var page = Math.floor(this.index/opts.pageSize)+2;
- if (this.r2.length){
- page++;
- }
- this.getRows.call(this, target, page, function(rows){
- if (!this.r2.length){
- this.r2 = rows;
- } else {
- this.r1 = this.r2;
- this.r2 = rows;
- this.index += opts.pageSize;
- }
- this.rows = this.r1.concat(this.r2);
- this.populate.call(this, target);
- });
- }
- }
-
- function reload(){
- var top = $(dc.body2).scrollTop();
- var index = Math.floor(top/25);
- var page = Math.floor(index/opts.pageSize) + 1;
-
- this.getRows.call(this, target, page, function(rows){
- this.index = (page-1)*opts.pageSize;
- this.rows = rows;
- this.r1 = rows;
- this.r2 = [];
- this.populate.call(this, target);
- dc.body2.triggerHandler(‘scroll.datagrid‘);
- });
- }
- }
- },
-
- getRows: function(target, page, callback){
- var state = $.data(target, ‘datagrid‘);
- var opts = state.options;
- var index = (page-1)*opts.pageSize;
- var rows = state.data.rows.slice(index, index+opts.pageSize);
- if (rows.length){
- callback.call(this, rows);
-
- } else {
- var param = $.extend({}, opts.queryParams, {
- page: page,
- rows: opts.pageSize
- });
- if (opts.sortName){
- $.extend(param, {
- sort: opts.sortName,
- order: opts.sortOrder
- });
- }
- if (opts.onBeforeLoad.call(target, param) == false) return;
-
- $(target).datagrid(‘loading‘);
- var result = opts.loader.call(target, param, function(data){
- $(target).datagrid(‘loaded‘);
- var data = opts.loadFilter.call(target, data);
- callback.call(opts.view, data.rows);
-
- }, function(){
- $(target).datagrid(‘loaded‘);
- opts.onLoadError.apply(target, arguments);
- });
- if (result == false){
- $(target).datagrid(‘loaded‘);
- }
- }
- },
-
- populate: function(target){
- var state = $.data(target, ‘datagrid‘);
- var opts = state.options;
- var dc = state.dc;
- var rowHeight = 25;
-
- if (this.rows.length){
- opts.view.render.call(opts.view, target, dc.body2, false);
- opts.view.render.call(opts.view, target, dc.body1, true);
-
- dc.body1.add(dc.body2).children(‘table.datagrid-btable‘).css({
- paddingTop: this.index*rowHeight,
- paddingBottom: state.data.total*rowHeight - this.rows.length*rowHeight - this.index*rowHeight
- });
- opts.onLoadSuccess.call(target, {
- total: state.data.total,
- rows: this.rows
- });
- }
- }
- });
分析结论
- virtualScrollView原理是通过设置div的上下padding来达到模拟极大数据量的效果的,我们只画比可视部分多一点的tr
- EasyUI的virtualScrollView支持两种方式:一是一次性请求完所有数据;二是每次都是ajax到pageSize条数据
- EasyUI的virtualScrollView画的tr数量是2*pageSize(初次加载例外,这时候只画1*pageSize的tr)
- EasyUI的virtualScrollView视图把行高强制视为25px的,如果你设置非25px的行高,这个视图就不能正常工作
- 因为只画2*pageSize个tr,所以我们dategrid的高度不能设置得超过2*25*pageSize个像素,超过的话就会造成可视区有留白
- 使用loadData方法加载数据的话loadData入参不需要total属性,只要是rows数组就可以了,total在loadData内部会自动计算
对于前面几点,大家自己看看源码里我写的注释,基础差的,看个似懂非懂就行了,基础好的,最好就彻底研究下。
存在的Bug
请求后台死循环
如果是url方式,第一次加载不到数据,就会不断地请求后台。看到146行了么,如果回调函数没有接受到rows,是不应该触发scorll事件的,因为scroll事件会请求后台数据,我已我们只要加上条件就行了:
- if(rows && rows.length > 0){
- dc.body2.triggerHandler(‘scroll.datagrid‘);
- }
二次请求后台
url方式下,如果后台返回数据不足以填充表格高度的时候,会重复请求后台(注意这地方只重复请求一次,跟第一个bug不同)。这个问题的原因也很简单,其实这种情况,datagrid高度有点大,但是后台又只有很少几条数据造成的,表现在只有一批数据,而这批数据又不足以填满这个表格可视区高度。我们把122行对getRows方法的调用加个条件就可以了:
- if (this.rows.length == opts.pageSize) {
- this.getRows.call(this, target, page, function(rows) {
- if (!this.r2.length) {
- this.r2 = rows;
- } else {
- this.r1 = this.r2;
- this.r2 = rows;
- this.index += opts.pageSize;
- }
- this.rows = this.r1.concat(this.r2);
- this.populate.call(this, target);
- });
- }
this.rows是当前已经画的一批rows,如果rows的条数没有pageSize大,那就说明不需要再请求数据了。
virtualScrollView是一种很好的优化手段,以后会被应用的越来越广的,EasyUI的VirtualScrollView视图是否支持editor我并有去尝试,估计是不支持的,有兴趣的同学可以去研究研究。
[JS][easyui]jQuery EasyUI Datagrid VirtualScrollView视图简单分析,布布扣,bubuko.com
[JS][easyui]jQuery EasyUI Datagrid VirtualScrollView视图简单分析
标签:des style java 使用 os 数据
原文地址:http://blog.csdn.net/szwangdf/article/details/37988421