我发现你的问题很有趣。在很多情况下,关于保存网格用户状态的问题很有趣。对于使用 cookie 的此类问题,有一些有趣的答案(例如,参见 here)。
在我看来,将网格状态保存在服务器上的数据库或localStorage 中是使用cookie 的更好方法。最佳方式取决于您使用它的项目要求。例如,使用服务器上的数据库存储允许您实现网格的漫游状态。如果您使用 localStorage 而不是 cookie,则如果用户转到另一台计算机或仅当用户将在同一台计算机上使用另一个 Web 浏览器时,用户首选项将会丢失。
网格状态的另一个问题是维护。您通常在 JavaScript 或 HTML 文件中而不是在数据库中保存的有关网格列的信息。在这种情况下,两个源不能在网格中的变化上同步。您可以轻松想象更新问题的不同场景。然而,在某些场景下,用户偏好的优势如此之大,以至于小劣势的问题并不那么重要,可以相对容易地解决。
所以我会花一些时间来实现两个演示,展示它是如何实现的。由于很多原因,我在演示中使用了localStorage。我从那里只提到两个:
- Cookie 是一种向服务器发送或从服务器发送永久不同信息的方式,而这并不是真正需要的。它会增加 HTTP 标头的大小并降低网站的性能(例如,请参阅 here)。
- Cookie 有非常严格的限制。对应于 rfc2109 的 6.3 或 rfc6265 的 6.1 部分:每个 cookie 至少 4096 个字节,每个域至少 50 个 cookie(在 rfc2109 中为 20 个),总共至少 3000 个 cookie(在 rfc2109 中为 300 个)。所以cookies不能用来保存太多的信息。例如,如果您要保存每个网页的每个网格的状态,您可以快速达到限制。
另一方面,localStorage 受到所有现代浏览器的支持,并将在从 IE8 开始的 Internet Explorer 中得到支持(请参阅here)。 localStorage 将自动保存每个来源(如 a1.example.com、a2.example.com、a3.example.com 等),并且每个来源有 5 MB 的任意限制(请参阅here)。因此,如果您仔细使用空间,您将远离任何限制。
所以我在演示中使用了localStorage。我还应该提一下,如果浏览器支持并使用其他存储,则有一些像jStorage 这样的插件使用localStorage,但对于像IE6/IE7 这样的旧浏览器,你的界面相同。如果您只有较小的存储空间:128 kB 而不是 5 MB,但最好是 4K,后者用于 cookie(请参阅here)。
现在关于实施。我创建了两个演示:this,它是扩展版本:this。
在the first 演示中,网格的以下状态将被保存并在页面重新加载时自动恢复(在大多数网络浏览器中为 F5):
- 隐藏了哪一列
- 列的顺序
- 每列的宽度
- 网格将被排序的列的名称和排序方向
- 当前页码
- 网格的当前过滤器和是否应用过滤器的标志。我在网格中使用了
multipleSearch: true 设置。
以同样的方式可以扩展(或减少)作为已保存网格状态一部分的选项列表。
您将在下面找到演示代码中最重要的部分:
var $grid = $("#list"),
saveObjectInLocalStorage = function (storageItemName, object) {
if (typeof window.localStorage !== 'undefined') {
window.localStorage.setItem(storageItemName, JSON.stringify(object));
}
},
removeObjectFromLocalStorage = function (storageItemName) {
if (typeof window.localStorage !== 'undefined') {
window.localStorage.removeItem(storageItemName);
}
},
getObjectFromLocalStorage = function (storageItemName) {
if (typeof window.localStorage !== 'undefined') {
return $.parseJSON(window.localStorage.getItem(storageItemName));
}
},
myColumnStateName = 'ColumnChooserAndLocalStorage.colState',
saveColumnState = function (perm) {
var colModel = this.jqGrid('getGridParam', 'colModel'), i, l = colModel.length, colItem, cmName,
postData = this.jqGrid('getGridParam', 'postData'),
columnsState = {
search: this.jqGrid('getGridParam', 'search'),
page: this.jqGrid('getGridParam', 'page'),
sortname: this.jqGrid('getGridParam', 'sortname'),
sortorder: this.jqGrid('getGridParam', 'sortorder'),
permutation: perm,
colStates: {}
},
colStates = columnsState.colStates;
if (typeof (postData.filters) !== 'undefined') {
columnsState.filters = postData.filters;
}
for (i = 0; i < l; i++) {
colItem = colModel[i];
cmName = colItem.name;
if (cmName !== 'rn' && cmName !== 'cb' && cmName !== 'subgrid') {
colStates[cmName] = {
width: colItem.width,
hidden: colItem.hidden
};
}
}
saveObjectInLocalStorage(myColumnStateName, columnsState);
},
myColumnsState,
isColState,
restoreColumnState = function (colModel) {
var colItem, i, l = colModel.length, colStates, cmName,
columnsState = getObjectFromLocalStorage(myColumnStateName);
if (columnsState) {
colStates = columnsState.colStates;
for (i = 0; i < l; i++) {
colItem = colModel[i];
cmName = colItem.name;
if (cmName !== 'rn' && cmName !== 'cb' && cmName !== 'subgrid') {
colModel[i] = $.extend(true, {}, colModel[i], colStates[cmName]);
}
}
}
return columnsState;
},
firstLoad = true;
myColumnsState = restoreColumnState(cm);
isColState = typeof (myColumnsState) !== 'undefined' && myColumnsState !== null;
$grid.jqGrid({
// ... other options
page: isColState ? myColumnsState.page : 1,
search: isColState ? myColumnsState.search : false,
postData: isColState ? { filters: myColumnsState.filters } : {},
sortname: isColState ? myColumnsState.sortname : 'invdate',
sortorder: isColState ? myColumnsState.sortorder : 'desc',
loadComplete: function () {
if (firstLoad) {
firstLoad = false;
if (isColState) {
$(this).jqGrid("remapColumns", myColumnsState.permutation, true);
}
}
saveColumnState.call($(this), this.p.remapColumns);
}
});
$grid.jqGrid('navButtonAdd', '#pager', {
caption: "",
buttonicon: "ui-icon-calculator",
title: "choose columns",
onClickButton: function () {
$(this).jqGrid('columnChooser', {
done: function (perm) {
if (perm) {
this.jqGrid("remapColumns", perm, true);
saveColumnState.call(this, perm);
}
}
});
}
});
$grid.jqGrid('navButtonAdd', '#pager', {
caption: "",
buttonicon: "ui-icon-closethick",
title: "clear saved grid's settings",
onClickButton: function () {
removeObjectFromLocalStorage(myColumnStateName);
}
});
注意将myColumnStateName(演示中的值`'ColumnChooserAndLocalStorage.colState'`)定义为不同页面上的不同值。
The second demo 是第一个使用我的old answer 到您的另一个问题的技术的扩展。该演示使用搜索工具栏,并在高级搜索表单和搜索工具栏之间同步附加信息。
更新:next answer 包含上述代码的扩展版本。它显示了如何另外持久化选定的行(或行)。 Another answer 展示了如何持久化树形网格的展开节点列表,并在页面重载时展开节点。