我一直在阅读论坛帖子和调整示例已经很多天了,并没有找到解决以下问题的方法。我正在评估大网格的创建(这里是包含许多列,行和特征的大表),我正在为此目的尝试Sencha ExtJS(我正在评估几个选项,Sencha似乎非常适合大网格)。
我的场景是我要创建一个网格,包括20k行,100多列,可变行高,分组,一些特殊渲染单元格(单元格中的表格)和使用缓冲渲染。我希望一次加载整个(假)数据,然后使用缓冲区渲染。我的问题是我的性能有问题(向下滚动)。我不确定应该指定什么来提高速度(每个单元格的直接行高,或者某些* bufferZone选项)。
我仍然是Sencha的初学者,所以我不确定我是否正确使用缓冲渲染(和缓冲存储)(只将pageSize和* bufferZone道具添加到网格本身)。因此,如果有人可以就我做错的事情提出建议,我将不胜感激。
Ext.Loader.setConfig({enabled: true});
Ext.Loader.setPath('Ext.ux', '../ux/');
Ext.require([
'Ext.grid.*',
'Ext.data.*',
'Ext.util.*',
'Ext.grid.plugin.BufferedRenderer'
]);
Ext.define('Employee', {
extend: 'Ext.data.Model',
fields: [{
name: 'employeeNo'
}, {
name: 'rating',
type: 'int'
}, {
name: 'salary',
type: 'float'
}, {
name: 'forename'
}, {
name: 'surname'
}, {
name: 'email'
}, {
name: 'department'
}, {
name: 'dob',
type: 'date',
dateFormat: 'Ymd'
}, {
name: 'joinDate',
type: 'date',
dateFormat: 'Ymd'
}, {
name: 'noticePeriod'
}, {
name: 'sickDays',
type: 'int'
}, {
name: 'holidayDays',
type: 'int'
}, {
name: 'holidayAllowance',
type: 'int'
},
'rowHeight'],
idField: 'employeeNo'
});
Ext.onReady(function() {
var COMPLEXITY_OVERFLOW = 3,
COMPLEXITY_MEDIUM = 2,
COMPLEXITY_SIMPLE = 1,
COMPLEXITY_DEFAULT = COMPLEXITY_SIMPLE;
var maxRows = 20000,
maxCols = 100,
scenario = COMPLEXITY_MEDIUM;
var fakeDataStore = Ext.create('Ext.data.Store', {
id: 'fakeDataStore',
groupField: 'department',
model: 'Employee'
//pageSize: 1000,
//trailingBufferZone: 80,
//leadingBufferZone: 50,
//purgePageCount: 0,
//buffered: false
// proxy: {
// type: 'memory'
// }
});
var cellEditing = Ext.create('Ext.grid.plugin.CellEditing', {
clicksToEdit: 1
});
function renderSimple(v, cellValues, rec) {
return rec.get('forename') + ' ' + rec.get('surname');
}
function renderHtmlTable(value, metaData, record, row, col, store, gridView) {
return "<table border='1' style='width:150px;'>"
+ "<tr><td>" + record.get('forename') + "</td><td>"+ record.get('surname') + "</td><td>50</td></tr>"
+ "<tr><td>" + record.get('forename') + "</td><td>"+ record.get('surname') + "</td><td>90</td></tr>"
+ "<tr><td>" + record.get('forename') + "</td><td>"+ record.get('surname') + "</td><td>30</td></tr></table>";
}
/*******************************/
/** DEFINE AND CREATE COLUMNS **/
var cols = [{
xtype: 'rownumberer', //col 1
width: 60,
//locked : true,
sortable: false,
xhooks: {
renderer: function(v, meta, record) {
meta.tdAttr = 'style="vertical-align:center;height:' + record.data.rowHeight + 'px"';
return this.callParent(arguments);
}
}
}, {
text: 'Id',//col 2
sortable: true,
// locked : true,
dataIndex: 'employeeNo',
groupable: false,
width: 70
}, {
text: 'Name',//col 3
sortable: true,
dataIndex: 'name',
groupable: false,
renderer: function(v, cellValues, rec) {
return rec.get('forename') + ' ' + rec.get('surname');
},
field: {
allowBlank: false
},
width: 120
},{
text: 'Complex',
dataIndex: 'name',
width: 200,
renderer: renderHtmlTable
},
{
text: 'Date of birth',//col 4
dataIndex: 'dob',
xtype: 'datecolumn',
groupable: false
}, {
text: 'Join date',//col 5
dataIndex: 'joinDate',
xtype: 'datecolumn',
groupable: false
}, {
text: 'Notice period',//col 6
dataIndex: 'noticePeriod',
groupable: false
}, {
text: 'Email address',//col 7
dataIndex: 'email',
width: 200,
groupable: false,
renderer: function(v) {
return '<a href="mailto:' + v + '">' + v + '</a>';
}
}, {
text: 'Department',//col 8 //NOT A COLUMN - it's hidden
dataIndex: 'department',
hidden: true,
hideable: false,
groupable: false
}, {
text: 'Work Related Info',
columns: [{
text: 'Absences',
columns: [{
text: 'Illness',//col 9
dataIndex: 'sickDays',
width: 40,
groupable: false
}, {
text: 'Holidays',//col 10
dataIndex: 'holidayDays',
width: 50,
groupable: false,
field: {
xtype: 'combobox',
typeAhead: true,
triggerAction: 'all',
selectOnTab: true,
store: [
[3,3],
[4,4],
[5,5]
],
lazyRender: true,
listClass: 'x-combo-list-small'
}
}, {
text: 'Holday Allowance',//col 11
dataIndex: 'holidayAllowance',
width: 50,
groupable: false
}]
}, {
text: 'Rating',//col 12
width: 50,
sortable: true,
dataIndex: 'rating',
groupable: false
}, {
text: 'Salary',//col 13
width: 110,
sortable: true,
dataIndex: 'salary',
align: 'right',
renderer: Ext.util.Format.usMoney,
groupable: false
},{
text: 'Rating',//col 14
width: 50,
sortable: true,
dataIndex: 'rating',
groupable: false
}, {
text: 'Salary',//col 15
width: 110,
sortable: true,
dataIndex: 'salary',
align: 'right',
renderer: Ext.util.Format.usMoney,
groupable: false
},{
text: 'Rating',//col 16
width: 50,
sortable: true,
dataIndex: 'rating',
groupable: false
}, {
text: 'Salary',//col 17
width: 110,
sortable: true,
dataIndex: 'salary',
align: 'right',
renderer: Ext.util.Format.usMoney,
groupable: false
}]
}];
/* add extra columns */
var maxExtraCols = maxCols;
/** what types of extra columns we should add */
if (scenario == COMPLEXITY_SIMPLE) {
for (var i = 0; i < maxExtraCols; i++) {
cols.push({
text: 'Name ' + i ,
sortable: false,
dataIndex: 'name',
groupable: false,
renderer: renderSimple,
width: 70
});
}
} else if (scenario == COMPLEXITY_MEDIUM) {
for (var i = 0; i < maxExtraCols; i++) {
cols.push({
text: 'Name ' + i ,
sortable: false,
dataIndex: 'name',
groupable: false,
renderer: (i % 2 == 0 ? renderHtmlTable : renderSimple),
width: 200
});
}
} else if (scenario == COMPLEXITY_OVERFLOW) {
//render more columns
var tempMax = maxExtraCols / 3;
for (var i = 0; i < tempMax; i++) {
cols.push({
text: 'Name ' + i ,
sortable: false,
dataIndex: 'name',
groupable: false,
renderer: renderSimple,
width: 70
});
}
var tempMax2 = tempMax * 2;
for (var i = tempMax; i < tempMax2; i++) {
cols.push({
text: 'Name ' + i ,
sortable: false,
dataIndex: 'name',
groupable: false,
renderer: renderHtmlTable,
width: 70
});
}
for (var i = tempMax2; i < maxExtraCols; i++) {
cols.push({
text: 'Name ' + i ,
sortable: false,
dataIndex: 'name',
groupable: false,
renderer: (i % 2 == 0 ? renderSimple : renderHtmlTable),
width: 60
});
}
}
/**********************/
/** CREATE GRID PANEL **/
console.log('Create grid begin');
var grid = Ext.create('Ext.grid.Panel', {
width: 1200,
height: 600,
title: 'Buffered Grid Testing',
store: fakeDataStore,
loadMask: true,
verticalScroller: {
variableRowHeight: true
},
invalidateScrollerOnRefresh: false,
// disableSelection: true,
plugins: [{
ptype: 'bufferedrenderer'
//numFromEdge: 20,
//trailingBufferZone: 40,
//leadingBufferZone: 80
}, cellEditing],
selModel: {
pruneRemoved: false
},
viewConfig: {
trackOver: false
},
features: [{
ftype: 'groupingsummary',
groupHeaderTpl: 'Department: {name}',
showSummaryRow: false
}],
// grid columns
columns: cols,
bbar: [{
labelWidth: 80,
fieldLabel: 'Jump to row',
xtype: 'numberfield',
minValue: 1,
maxValue: maxRows,
allowDecimals: false,
itemId: 'gotoLine',
enableKeyEvents: true,
listeners: {
specialkey: function(field, e){
if (e.getKey() === e.ENTER) {
jumpToRow();
}
}
}
}, {
text: 'Go',
handler: jumpToRow
}],
renderTo: Ext.getBody()
});
var jumpToRow = function(){
var fld = grid.down('#gotoLine');
if (fld.isValid()) {
grid.view.bufferedRenderer.scrollTo(fld.getValue() - 1, true);
}
};
/**********************/
/** CREATE FAKE DATA**/
var data = [];
function random(from, to) {
return Math.floor(Math.random() * (to - from + 1) + from);
}
function getEmployeeNo() {
var out = '',
i = 0;
for (; i < 6; ++i) {
out += random(0, 7);
}
return out;
}
/**
* Returns an array of fake data
* @param {Number} count The number of fake rows to create data for
* @return {Array} The fake record data, suitable for usage with an ArrayReader
*/
function createFakeData(count, data) {
var firstNames = ['Ed', 'Tommy', 'Aaron', 'Abe', 'Jamie', 'Adam', 'Dave', 'David', 'Jay', 'Nicolas', 'Nige'],
lastNames = ['Spencer', 'Maintz', 'Conran', 'Elias', 'Avins', 'Mishcon', 'Kaneda', 'Davis', 'Robinson', 'Ferrero', 'White'],
departments = ['Engineering', 'Sales', 'Marketing', 'Managment', 'Support', 'Administration'],
ratings = [1, 2, 3, 4, 5],
salaries = [100, 400, 900, 1500, 1000000],
noticePeriods= ['2 weeks', '1 month', '3 months'],
i;
for (i = 0; i < (count || 25); i++) {
var firstName = firstNames[random(0, firstNames.length - 1)],
lastName = lastNames[random(0, lastNames.length - 1)],
name = Ext.String.format("{0} {1}", firstName, lastName),
email = firstName.toLowerCase() + '.' + lastName.toLowerCase() + '@sentcha.com',
rating = ratings[(name === 'Nige White') ? 0 : random(0, ratings.length - 1)],
salary = salaries[(name === 'Nige White') ? 4 : random(0, salaries.length - 1)],
department = departments[random(0, departments.length - 1)],
ageInYears = random(23, 55),
dob = new Date(new Date().getFullYear() - ageInYears, random(0, 11), random(0, 31)),
joinDate = new Date(new Date() - random(60, 2000) * 1000 * 60 * 60 * 24),
sickDays = random(0, 10),
holidayDays = random(0, 10),
holidayAllowance = random(20, 40);
data.push({
employeeNo: getEmployeeNo(),
rating: rating,
salary: salary,
forename: firstName,
surname: lastName,
email: email,
department: department,
dob: dob,
joinDate: joinDate,
sickDays: sickDays,
holidayDays: holidayDays,
holidayAllowance: holidayAllowance,
noticePeriod: noticePeriods[random(0, noticePeriods.length - 1)],
rowHeight: (i == count - 1) ? 150 : Ext.Number.randomInt(85, 110)
});
}
}
function makeData() {
//create fake data
var start = new Date().getTime();
createFakeData(maxRows, data);
var end = new Date().getTime();
var time = end - start;
console.log('Total time to create fake data: ' + time)
//load data to store
start = new Date().getTime();
fakeDataStore.loadData(data);
end = new Date().getTime();
time = end - start;
console.log('Total time to load fake data: ' + time)
}
makeData();
})
我知道使用许多列和可变行高确实会对性能产生影响。但是,我已经看到网格中的无限滚动与调谐器示例,它允许大量的列,仍然可以正常工作。
对我的“假数据”使用缓冲存储会引发一些关于我启用了分组的问题;没有分组它抱怨没有我的数据存储区的URL。在我的场景中,不确定如何组合所有设置以使滚动工作正常(可接受的性能意味着没有冻结视口)。
答案 0 :(得分:0)
虽然答案是依赖于场景的(相对于商店/数据),但是在快餐中,快速渲染的想法似乎是使用滚动(缓冲存储和渲染):
它是一个或者其他..你不能加载所有数据,然后缓冲它.. 缓冲的整个目标是仅加载可查看的内容( 缓冲区顶部和底部)
有关详细信息和更长时间的讨论,请参阅this。
另请参阅ExtJS&#34;无限滚动调谐器&#34;演示示例(来自可下载的软件包)。
请随时添加有关此主题的更多输入/反馈。