頁面上存在定時重新整理表格的功能,而且表格中每行又有詳情,當每次重新整理每行時,即執行了Record的Set方法,詳情都會關閉。剛開始覺得很奇怪。因為我一直覺得,我重新整理一行中的一個欄位的話,那應該是只更新這個欄位的DOM就行了。
後台查看了一下原始碼原來,每個Record資料變化時,其實都是重建一條新行的DOM。在原始碼的執行步驟是,先新插入一行,再把舊資料的行DOM刪除換。
由於詳情是屬於行的,所以,每次執行Record的Set後,行重建,那麼詳情肯定會刪除掉。
為瞭解決詳情不關閉這個問題,我們想方法為Record自訂一個Replace方法出來。
它的功能是:使用Record的Replace方法,可以實現單個欄位的更新。
看起來很空間的一句話,可是為了實現這個功能,重寫了ExtJs很多的“類”才實現了。下面是為了實現這個功能代碼,
還帶了實現了一個功能,使用ExtJs提供的冒泡提示加到表格的欄位值中。
Ext.onReady(function(){
//要使用ExtJS提供的冒泡提示,必須加上下面這句
Ext.QuickTips.init();
Ext.override(Ext.grid.ColumnModel,{
//根據列定義時的給出的ID,得到該列的渲染方法,其實是為了更新單個儲存格時,顯示與定義一致
getRendererById:function(id){
return this.getRenderer(this.getIndexById(id));
}
});
//步驟4:
Ext.data.Record.REPLACE = 'repalce';//定義一個記錄的替換命令,目前沒有什麼作用
Ext.override(Ext.data.Record,{
//替換單個欄位的值的方法
replace : function(name, value){
var encode = Ext.isPrimitive(value) ? String : Ext.encode;
if(encode(this.data[name]) == encode(value)) {
return;
}
this.dirty = true;
if(!this.modified){
this.modified = {};
}
if(this.modified[name] === undefined){
this.modified[name] = this.data[name];
}
this.data[name] = value;//模型更新
this.afterReplace(name,value);//通過Store通知gridview視圖更新
},
//通過Store通知gridview視圖更新方法
afterReplace:function(name,value){
if (this.store != undefined && typeof this.store.afterReplace == "function") {
this.store.afterReplace(this,name,value);
}
}
});
//步驟5:
Ext.override(Ext.data.Store,{
//新定義的通知gridview視圖更新的方法
afterReplace : function(record,name,value){
if(this.modified.indexOf(record) == -1){
this.modified.push(record);
}
//通知視圖更新
this.fireEvent('repalce',record,name,value, Ext.data.Record.REPLACE);
}
}
);
var myData = [
['3m Co',71.72,0.02,0.03,'9/1 12:00am'],
['Alcoa Inc',29.01,0.42,1.47,'9/1 12:00am'],
['Altria Group Inc',83.81,0.28,0.34,'9/1 12:00am']
];
// example of custom renderer function
function change(val){
if(val > 0){
return '<span qtip="'+val+'" style="color:green;">' + val + '</span>';
}else if(val < 0){
return '<span qtip="'+val+'" style="color:red;">' + val + '</span>';
}
return val;
}
//使用ExtJS提供的冒泡提示
function titleQtip(val){貨運專家
return '<span qtip="'+val+'">' + val + '</span>';
}
// example of custom renderer function
function pctChange(val){
if(val > 0){
return '<span style="color:green;">' + val + '%</span>';
}else if(val < 0){
return '<span style="color:red;">' + val + '%</span>';
}
return val;
}
// create the data store
var store = new Ext.data.Store({
proxy: new Ext.ux.data.PagingMemoryProxy(myData),
remoteSort:true,
sortInfo: {field:'price', direction:'ASC'},
reader: new Ext.data.ArrayReader({
fields: [
{name: 'company'},
{name: 'price', type: 'float'},
{name: 'change', type: 'float'},
{name: 'pctChange', type: 'float'},
{name: 'lastChange', type: 'date', dateFormat: 'n/j h:ia'}
]
})
});
Ext.override(Ext.grid.GridView,{
////步驟7:真正實現GridView更新單個儲存格的方法
onReplace:function(record,name,value){
var ds = this.ds, index;
if(Ext.isNumber(record)){
index = record;
record = ds.getAt(index);
if(!record){
return;
}
}else{
index = ds.indexOf(record);
if(index < 0){
return;
}
}
//實現單個欄位的更新
document.getElementById(index+name).innerHTML = this.cm.getRendererById(name).call(this,value);
},
//步驟6:
initData : function(ds, cm){
if(this.ds){
this.ds.un('load', this.onLoad, this);
this.ds.un('datachanged', this.onDataChange, this);
this.ds.un('add', this.onAdd, this);
this.ds.un('remove', this.onRemove, this);
this.ds.un('update', this.onUpdate, this);
this.ds.un('clear', this.onClear, this);
//表格銷毀時把這個監聽放棄
this.ds.un('repalce', this.onReplace, this);
if(this.ds !== ds && this.ds.autoDestroy){
this.ds.destroy();
}
}
if(ds){
ds.on({
scope: this,
load: this.onLoad,
datachanged: this.onDataChange,
add: this.onAdd,
remove: this.onRemove,
update: this.onUpdate,
clear: this.onClear,
//當表格載入Store時,把這個監聽添加上
repalce: this.onReplace
});
}
this.ds = ds;
if(this.cm){
this.cm.un('configchange', this.onColConfigChange, this);
this.cm.un('widthchange', this.onColWidthChange, this);
this.cm.un('headerchange', this.onHeaderChange, this);
this.cm.un('hiddenchange', this.onHiddenChange, this);
this.cm.un('columnmoved', this.onColumnMove, this);
}軟體開發
if(cm){
delete this.lastViewWidth;
cm.on({
scope: this,
configchange: this.onColConfigChange,
widthchange: this.onColWidthChange,
headerchange: this.onHeaderChange,
hiddenchange: this.onHiddenChange,
columnmoved: this.onColumnMove
});
}
this.cm = cm;
},
doRender : function(columns, records, store, startRow, colCount, stripe) {
var templates = this.templates,
cellTemplate = templates.cell,
rowTemplate = templates.row,
last = colCount - 1;
var tstyle = 'width:' + this.getTotalWidth() + ';';
// buffers
var rowBuffer = [],
colBuffer = [],
rowParams = {tstyle: tstyle},
meta = {},
column,
record;
//build up each row's HTML
for (var j = 0, len = records.length; j < len; j++) {
record = records[j];
colBuffer = [];
var rowIndex = j + startRow;
//build up each column's HTML
for (var i = 0; i < colCount; i++) {
column = columns[i];
meta.id = column.id;
meta.css = i === 0 ? 'x-grid3-cell-first ' : (i == last ? 'x-grid3-cell-last ' : '');
meta.attr = meta.cellAttr = '';
meta.style = column.style;
meta.value = column.renderer.call(column.scope, record.data[column.name], meta, record, rowIndex, i, store);
//步驟2:定義這個欄位的DIV的ID,這個地方是關鍵,否則我們通過document.getElementById找不到這個DIV,也就不可以實現這個功能了。
meta.divId = j+column.name;
if (Ext.isEmpty(meta.value)) {
meta.value = ' ';
}
if (this.markDirty && record.dirty && Ext.isDefined(record.modified[column.name])) {
meta.css += ' x-grid3-dirty-cell';
}
colBuffer[colBuffer.length] = cellTemplate.apply(meta);
}
//set up row striping and row dirtiness CSS classes
var alt = [];
if (stripe && ((rowIndex + 1) % 2 === 0)) {
alt[0] = 'x-grid3-row-alt';
}
if (record.dirty) {
alt[1] = ' x-grid3-dirty-row';
}
rowParams.cols = colCount;
if (this.getRowClass) {
alt[2] = this.getRowClass(record, rowIndex, rowParams, store);
}
rowParams.alt = alt.join(' ');
rowParams.cells = colBuffer.join('');
rowBuffer[rowBuffer.length] = rowTemplate.apply(rowParams);
}
return rowBuffer.join('');
}
});
var ts = {};
ts.cell = new Ext.Template('<td class="x-grid3-col x-grid3-cell x-grid3-td-{id} {css}" style="{style}" tabIndex="0" {cellAttr}>',
//步驟1:本來是開啟在GridView重寫這部分,可是發現代碼太多,覺得沒有必要,在這裡直接定義為Div添加一個id的屬性即可。
'<div id=\'{divId}\' class="x-grid3-cell-inner x-grid3-col-{id}" unselectable="on" {attr}>{value}</div>','</td>');
// create the Grid
var grid = new Ext.grid.GridPanel({
store: store,
//步驟3:注意在添加這個屬性
viewConfig:{
templates:ts
},
columns: [
{id:'company',header: "Company", width: 160, sortable: true,renderer: titleQtip, dataIndex: 'company'},
{header: "Price", width: 75, sortable: true, renderer: 'usMoney', dataIndex: 'price'},
{id:'change',header: "Change", width: 75, sortable: true, renderer: change, dataIndex: 'change'},
{header: "% Change", width: 75, sortable: true, renderer: pctChange, dataIndex: 'pctChange'},
{header: "Last Updated", width: 85, sortable: true, renderer: Ext.util.Format.dateRenderer('m/d/Y'), dataIndex: 'lastChange'}
],
stripeRows: true,
autoExpandColumn: 'company',
height:320,
width:600,
frame:true,
title:'Sliding Pager',
id:'maingrid',
plugins: new Ext.ux.PanelResizer({
minHeight: 100
}),
bbar: new Ext.PagingToolbar({
pageSize: 10,
store: store,
displayInfo: true
})
});
grid.render('grid-example');
store.load({params:{start:0, limit:10}});
//alert(document.getElementById('1pctChange').innerHTML);
});
//測試該功能的代碼
function change(){
//修改第2行的company這個欄位的值
Ext.getCmp('maingrid').store.getAt(1).replace('company','ddddd');
}