Extjs4.2 grid页面自定义布局 持久化
声明
-
本文重点讲解持久化到服务端的思路,如果不用持久化到服务端也是可以借鉴思路的,一般也可以保存到本地cookie中;
-
本文主要讲解表格的隐藏、表格的宽度、是否排序、列顺序的持久化功能,包括:取消排序、保存布局、重置布局;
-
本人作为Extjs的初学者,对Extjs的熟悉度并不高,如有讲解不合理的地方,望指正;
-
以下编码思路基于其他网友给的思路,本篇文章只是作为一种解决方案,希望也能给需要思路的你带来一点灵感;
-
以下正文有部分编码来自于网友博客,如有需要,可以进行查看:网友原文地址
以下是我理解的一些思路
- 整体思路:客户端拿到列头信息,传给服务端,服务端进行持久化操作即可;
- 在表头的倒三角下来按钮中新增按钮:取消排序、保存布局、重置布局;
- 当我们点击保存布局的时候,客户端可以把表头信息记录下来,经过加工整理后,传递给服务端进行持久化;
- 当我点击取消排序的时候,我们拿到取消的具体条件到服务端清空需要取消排序的数据即可;
- 当我们点击重置布局的时候,我们需要拿到相应的条件去服务端清空相应的数据即可;
好吧,思路看似简单,但如果你是跟我一样不熟悉Extjs架构的人,还是稍稍有些困难,那我们再从Extjs的角度来构思具体实现吧!
构思具体实现
- 思考几个问题:
1.在哪里给倒三角加菜单按钮,什么时候加;
2.所谓的列头信息,具体是指什么;
3.列头信息如何加工处理比较好;
4.还有其他的注意思想吗?
经过以上几个问题,我在这里根据我的理解进行如下解答(参照网友的编码思路):
1.在哪里给倒三角加菜单按钮,什么时候加;
答:在Grid页面初始化的时候可以给grid添加按钮。
2.所谓的列头信息,具体是指什么;
答:Grid的Column信息就是列头信息。
3.列头信息如何加工处理比较好;
答:把表格的隐藏、表格的宽度、是否排序、列顺序、列名称等作为字段传递给服务端。
4.还有其他的注意思想吗?
答:有一点不能少,那就是我们要知道哪些页面开启了需要进行列表布局持久化的,比如我们可用:stateful: true
来开启列表布局持久化,在页面初始化的时候,我们检测到stateful=true 了,就表明此页面开启了持久化布局,我们就可以生成倒三角按钮;我们也要知道我们这是哪一个页面,我们可以用 stateId: 'PageId01'
来表示,当我们保存布局的时候把这个stateid与列头信息一起传递给服务端!
具体代码实现
1.重写Grid:
Ext.define('StatefulGrid', {
extend: 'Ext.grid.Panel',
alias: 'widget.statefulgrid',
requires: ['UISettingsSvc'],
initComponent: function() {
var me = this;
if (Ext.isArray(me.columns)) {
// 默认列标题居中显示并自动换行
for (var i in me.columns) {
me.columns[i].cls = 'pds-header-center';
}
}
me.callParent();
//如果没有配置则默认为不用持久化布局
if (Ext.isEmpty(me.stateId)) {
return;
}
//默认加载
UISettingsSvc.loadState(me.getStateId());
// 应用UI配置
var state = UISettingsSvc.get(me.getStateId());
if (state) {
me.applyState(state);
}
// 添加菜单,允许恢复默认布局
me.headerCt.on('menucreate', function (headerCt, menu) {
var menu = me.headerCt.getMenu();
menu.add('-', {
text: '取消排序',
iconCls: 'resume',
handler: function (item) {
var m = item.ownerCt;
//console.log(m.tv);
var cols = me.columns;
var col = null,
bs = false;
for (var i = 0; i < cols.length; i++) {
col = cols[i];
if (col.sortState) {
bs = true;
col.removeCls([col.ascSortCls, col.descSortCls]);
col.sortState = null;
}
}
if (bs) {
me.getStore().sorters.removeAll();
me.getStore().reload();
}
UISettingsSvc.clearSort(me.getStateId());
}
}, {
text: '保存布局',
iconCls: 'save',
itemId: 'sateState',
handler: function (item, e) {
UISettingsSvc.saveState(me, me.getStateId(), me.getState());
}
}, {
text: '重置布局',
iconCls: 'reset',
itemId: 'resetState',
handler: function (item, e) {
UISettingsSvc.clearState(me, me.getStateId(), function () {
location = location;
});
}
});
});
}
});
2.编写工具类:
Ext.define('UISettingsSvc', {
extend: 'Ext.state.Provider',
singleton: true,
alternateClassName: 'UISettingsSvc',
/**
* 加载配置,一般要界面首次加载时调用
*/
loadState: function (firstParm) {
var me = this,columns = [], sorters = [], val = {
columns: null,
storeState: {
sorters: null
}
};
Ext.Ajax.request({
url: '你的请求地址',
params: {pageName: firstParm},
async: false,
success: function (response, opts) {
var ret = Ext.JSON.decode(response.responseText), fieldVOs, jsonData, sorterData;
if (ret.length == 0) {
val = null;
} else {
fieldVOs = ret[0].dataShowColumnFieldVOs;
if (fieldVOs.length > 0) {
for (var i = 0; i < fieldVOs.length; i++) {
var fv = fieldVOs[i];
jsonData = {
'id': fv.fieldShowNumber
};
if (fv.fieldIsnotShow == 't') {
jsonData.hidden = true;
}else {
jsonData.hidden = false;
}
if (fv.fieldIsnotHideable == 't') {
jsonData.hideable = true;
}else if (fv.fieldIsnotHideable == 'f'){
jsonData.hideable = false;
}
if (fv.fieldIsnotTristatesort == 't') {
jsonData.triStateSort = true;
}else if(fv.fieldIsnotTristatesort == 'f'){
jsonData.triStateSort = false;
}
if (fv.fieldIsnotSortable == 't') {
jsonData.sortable = true;
}else if((fv.fieldIsnotSortable == 'f')){
jsonData.sortable = false;
}
if (!Ext.isEmpty(fv.fieldIsnotCls)) {
jsonData.cls = fv.fieldIsnotCls;
}
if (fv.fieldLong != null) {
jsonData.width = fv.fieldLong;
}
columns[fv.orderNumber] = jsonData;
if (!Ext.isEmpty(fv.fieldIsnotDesc)) {
var direction = fv.fieldIsnotDesc;
if (direction == 'A') direction = 'ASC'; else direction = 'DESC';
sorterData = {
'direction': direction,
'property': fv.fieldName,
'root': 'data'
};
if (!sorters.length) {
sorters[0] = sorterData;
} else {
sorters[sorters.length] = sorterData;
}
}
}
}
}
}
});
if (val != null) {
val.columns = columns;
val.storeState.sorters = sorters;
}
me.state[firstParm] = val;
},
/**
* 获取控件状态
*
* @param {}
* name
* @param {}
* defaultValue
* @return {}
*/
get: function (name, defaultValue) {
// 防止状态被外部直接修改
return Ext.clone(typeof this.state[name] == "undefined" ? defaultValue : this.state[name]);
},
/**
* 重置布局时,清理后台的状态信息
*
* @param {}
* cmp
* @param {}
* name
* @param {}
* callback
*/
clearState: function (cmp, name, callback) {
var me = this;
if (!me.state[name]) {
if (callback)
callback();
return;
}
这里用页面Id去服务端清空布局信息
delete me.state[name];
if (callback)
callback();
},
/**
* 保存布局
*
* @param {}
* cmp
* @param {}
* name
* @param {}
* value
* @param {}
* callback
*/
saveState: function (cmp, name, value, callback) {
var me = this;
if (typeof value == "undefined" || value === null) {
me.clearState(name, callback);
return;
}
if (me.state[name] != value) {
var context, parmArr = [];
for (var i = 0; i < value.columns.length; i++) {
parmArr[i] = {
'fieldShowNumber': value.columns[i].id,//记录列id,即headerId
'fieldIsnotShow': me.fieldIsnotShow(cmp,value, i),//是否显示
'fieldName': me.fieldName(cmp, i),//列名
'fieldLong': me.fieldLong(value, i),//列宽
'fieldIsnotDesc': me.fieldIsnotDesc(value, i, cmp),//列排序方式
'orderNumber': i,//列顺序
'fieldIsnotHideable': me.istorf(cmp.columns[i].initialConfig.hideable),//me.fieldIsnotHideable(cmp, i),//是否不在倒三角可勾选显示隐藏中进行显示
'fieldIsnotCls': cmp.columns[i].initialConfig.cls,//列的Css样式
'fieldIsnotTristatesort': me.istorf(cmp.columns[i].initialConfig.triStateSort),//
'fieldIsnotSortable': me.istorf(cmp.columns[i].initialConfig.sortable)
};
}
这里把这些封装好的数据发个服务端进行持久化
me.state[name] = value;
}
},
fieldName: function (cmp, i) {
var dataIndex = cmp.columns[i].initialConfig.dataIndex;
if (!dataIndex) {
dataIndex = 'rownumberer';
}
return dataIndex;
},
istorf : function(value){
if (value) return 't';else if(value == undefined)return ;else return 'f';
},
fieldIsnotShow: function (cmp,value, i) {
var hid = value.columns[i].hidden;
if (hid) {
return 't';
} else{
if(hid!=undefined&&hid==false){
return 'f';
} else if(hid==undefined&&cmp.columns[i].initialConfig.hidden){
return 't';
}
}
},
fieldLong: function (value, i) {
var width = value.columns[i].width;
if (width != undefined) {
return width;
} else {
return null;
}
},
fieldIsnotDesc: function (value, i, cmp) {
var me = this;
if (!value.storeState) return null;
var len = value.storeState.sorters.length, fieldName;
fieldName = me.fieldName(cmp, i);
if (len > 0) {
for (var j = 0; j < len; j++) {
if (value.storeState.sorters[j].property == fieldName) {
if (value.storeState.sorters[j].direction == 'ASC') return 'A';
else if (value.storeState.sorters[j].direction == 'DESC') return 'D';
else return null;
} else return null;
}
}
},
/**
* 清除排序
* parm grid的唯一标识StateId
*/
clearSort : function (name) {
这里用页面Id去服务端清空排序信息
}
});
3.自己的Grid怎么写
Ext.define('MyGrid', {
extend: 'StatefulGrid',
xtype: 'myGrid',
alias: 'widget.myGrid',
store: 'MyStores',
stateId: 'Page01Id',//页面ID
stateful: true,//是否开启自定义排序
columns: column_,
bbar: ..
})
这样就简单实现了!
需要注意的是,我们在做弹窗表格的时候,由于列的headerId是Extjs底层随机生成的,以至于我们的保存列表布局只对某一个表格有效,这时候我们需要在columns中写死headerId的!
有人会问headerId是什么,当你断点调试的时候看见header-100这类似的数据的时候你就不会陌生了