location.hash保存页面状态的技巧


Posted in Javascript onApril 28, 2016

hash 属性是一个可读可写的字符串,该字符串是 URL 的锚部分(从 # 号开始的部分)。

语法

location.hash

在我们的项目中,有大量ajax查询表单+结果列表的页面,由于查询结果是ajax返回的,当用户点击列表的某一项进入详情页之后,再点击浏览器回退按钮返回ajax查询页面,这时大家都知道查询页面的表单和结果都回到了默认状态。

如果每次返回页面都要重新输入查询条件,或有甚者还得转到列表的第几页,那这种体验用户真的要抓狂了。

在我们的项目中,写了一个很简单的JavaScript基类来处理location.hash从而保存页面状态,今天在此就分享给大家。

(本文的内容可能对于JavaScript初学者来讲有点难度,因为涉及到JS面向对象的知识,如定义类、继承、虚方法、反射等)

先看看我们的需求

我们的项目是一个基于微信的H5任务管理系统,要完成的页面原型如下图所示:

location.hash保存页面状态的技巧

需求应该都很清晰,就是点击查询表单,用ajax返回查询结果,然后点击列表中的某一个任务进入任务详情页。由于管理员(项目经理)通常会一次处理多个任务,所以就会不断在任务详情页跟查询列表页切换,这时如果按返回键不能保存查询页面状态的话,那每次返回查询页面都要重新输入查询条件,这样的体验肯定是不能忍受的。

所以,我们需要想办法将页面状态保存下来,以便用户按回退键的时候,查询条件和结果都还在。

解决思路

保存页面状态的思路有很多啦,但是我们觉得用location.hash应该是最好的方法。

思路如下:

1.用户输入查询条件并点击确定后,我们将查询条件序列化成一个字符串,并通过“#”将查询条件加到url后面得到一个新的url,然后调用location.replace(新的url)修改浏览器地址栏中的地址。

2.当用户按回退键回退到查询页面时,也可以说是页面加载时,将location.hash反序列化成查询条件,然后将查询条件更新到查询表单并执行查询即可。

思路很简单,关键的地方就是location.replace方法,这个方法不仅仅是修改浏览器中地址栏的url,更重要的是会在window.history中替换当前页面的记录。如果不用location.replace方法,那么每次回退都会回退到上一个查询条件。当然,这样的需求可能对某些项目还有用。

最终解决方案

如果本文只是分享上面的解决思路,那价值就不大了。本文的价值应该是我们写的那个虽然简单但是却很强大的JavaScript类。

如果你看明白了上面的解决思路,那就看看这个简单的JavaScript类吧:

(function() {
if (window.HashQuery) {
return;
}
window.HashQuery = function() {
};
HashQuery.prototype = {
parseFromLocation: function() {
if (location.hash === '' || location.hash.length === ) {
return;
}
var properties = location.hash.substr().split('|');
var index = ;
for (var p in this) {
if (!this.hasOwnProperty(p) || typeof this[p] != 'string') {
continue;
}
if (index < properties.length) {
this[p] = properties[index];
if (this[p] === '-') {
this[p] = '';
}
}
index++;
}
},
updateLocation: function() {
var properties = [];
for (var p in this) {
if (!this.hasOwnProperty(p) || typeof this[p] != 'string') {
continue;
}
var value = this[p];
properties.push(value === '' ? '-' : value);
}
var url = location.origin + location.pathname + location.search + "#" + properties.join('|');
location.replace(url);
}
};
})();

这个类只有2个方法,HashQuery.parseFromLocation() 方法从location.hash反序列化为HashQuery子类的实例,HashQuery.updateLocation() 方法将当前HashQuery子类的实例序列化并更新到window.location。

可以看到HashQuery这个类没有任何属性,那是因为我们只定义了一个基类,类的属性都在子类中进行定义。这也是符合实际的,因为查询条件都只有在具体的页面才知道有哪些属性。

另外,请注意这里的序列化和反序列化。这里的序列化仅仅是利用JavaScript反射机制将实例的所有字符串属性(按顺序)的值用“|”分隔;而序列化则是将字符串用“|”分隔后,再利用反射更新到实例的属性(按顺序)。

如何使用HashQuery类

使用的时候就非常简单了。

第一步,定义一个子类,将需要用到的查询条件都加到字符串属性当中,如我们的代码:

(function() {
window.TaskSearchHashQuery = function () {
HashQuery.constructor.call(this);
this.iterationId = '';
this.assignedUserId = '';
this.status = '';
this.keyword = '';
};
TaskSearchHashQuery.constructor = TaskSearchHashQuery;
TaskSearchHashQuery.prototype = new HashQuery();
})();

第二步,在查询页面调用HashQuery.parseFromLocation() 和 HashQuery.updateLocation()方法即可。下面的代码是我们完整的查询页面:

(function() {
var urls = {
list: "/app/task/list"
};
var hashQuery = null;
var pager = null;
$(document).ready(function () {
hashQuery = new TaskSearchHashQuery();
hashQuery.parseFromLocation();//在这里调用的哦,从location反序列化object
updateFormByHashQuery();
$("#btnSearch").click(function() {
updateHashQueryByForm();
hashQuery.updateLocation();//在这里调用的哦,将查询条件序列化之后更新到location.hash
$("#lblCount").html("加载中...");
pager.reload();
page.hideSearch();
});
pager = new ListPager("#listTasks", urls.list);
pager.getPostData = function(index) {
return "pageIndex=" + index + "&pageSize=" + "&projectId=" + page.projectId
+ "&iterationId=" + hashQuery.iterationId
+ "&assignedUserId=" + hashQuery.assignedUserId
+ "&status=" + hashQuery.status
+ "&keyword=" + hashQuery.keyword;
};
pager.onLoaded = function() {
$("#lblCount").html("共 " + $("#hfPagerTotalCount").val() + " 个任务");
$("#hfPagerTotalCount").remove();
};
pager.init();
});
function updateHashQueryByForm() {
hashQuery.iterationId = $("#ddlIterations").val();
hashQuery.assignedUserId = $("#ddlUsers").val();
hashQuery.status = $("#ddlStatuses").val();
hashQuery.keyword = $("#txtKeyword").val();
};
function updateFormByHashQuery() {
$("#ddlIterations").val(hashQuery.iterationId);
$("#ddlUsers").val(hashQuery.assignedUserId);
$("#ddlStatuses").val(hashQuery.status);
$("#txtKeyword").val(hashQuery.keyword);
};
})();

总结

这就是我们项目中使用location.hash来保存页面状态的全部知识了。不知道大家的WEB项目中是如何处理这样的需求的呢?

以上内容是小编给大家介绍的location.hash保存页面状态的技巧,希望对大家有所帮助!

Javascript 相关文章推荐
JavaScript 工具库 Cloudgamer JavaScript Library v0.1 发布
Oct 29 Javascript
基于jquery的$.ajax async使用
Oct 19 Javascript
js对象关系图 方便dom操作
Mar 18 Javascript
jquery1.10给新增元素绑定事件的方法
Mar 06 Javascript
jQuery结合ajax实现动态加载文本内容
May 19 Javascript
JavaScript遍历求解数独问题的主要思路小结
Jun 12 Javascript
微信小程序 实现tabs选项卡效果实例代码
Oct 31 Javascript
AngularJS中的JSONP实例解析
Dec 01 Javascript
自定义vue全局组件use使用、vuex的使用详解
Jun 14 Javascript
Webpack如何引入bootstrap的方法
Jun 17 Javascript
jquery 动态遍历select 赋值的实例
Sep 12 jQuery
Vue之Mixins(混入)的使用方法
Sep 24 Javascript
字符串反转_JavaScript
Apr 28 #Javascript
使用 stylelint检查CSS_StyleLint
Apr 28 #Javascript
基于BootStarp的Dailog
Apr 28 #Javascript
浅析jquery与checkbox的checked属性的问题
Apr 27 #Javascript
JavaScript 消息框效果【实现代码】
Apr 27 #Javascript
浅析jQuery事件之on()方法绑定多个选择器,多个事件
Apr 27 #Javascript
js实现人民币大写金额形式转换
Apr 27 #Javascript
You might like
php函数array_merge用法一例(合并同类数组)
2013/02/03 PHP
PHP数据过滤的方法
2013/10/30 PHP
php实现cookie加密的方法
2015/03/10 PHP
PHP超牛逼无限极分类生成树方法
2015/05/11 PHP
php-redis中的sort排序函数总结
2015/07/08 PHP
CI映射(加载)数据到view层的方法
2016/03/28 PHP
yii2利用自带UploadedFile实现上传图片的示例
2017/02/16 PHP
PHP new static 和 new self详解
2017/02/19 PHP
InnerHtml和InnerText的区别分析
2009/03/13 Javascript
JQuery实现点击div以外的位置隐藏该div窗口
2013/09/13 Javascript
javascript生成随机大小写字母的方法
2014/02/20 Javascript
JS实现的4种数字千位符格式化方法分享
2015/03/02 Javascript
浅谈JavaScript正则表达式分组匹配
2015/04/10 Javascript
分分钟学会vue中vuex的应用(入门教程)
2017/09/14 Javascript
微信小程序基于本地缓存实现点赞功能的方法
2017/12/18 Javascript
Vue实现搜索 和新闻列表功能简单范例
2018/03/16 Javascript
js实现web调用摄像头 js截取视频画面
2019/04/21 Javascript
vue的keep-alive用法技巧
2019/08/15 Javascript
JQuery实现ul中添加LI和删除指定的Li元素功能完整示例
2019/10/16 jQuery
vue+elementUI(el-upload)图片压缩,默认同比例压缩操作
2020/08/10 Javascript
使用python装饰器验证配置文件示例
2014/02/24 Python
python数组复制拷贝的实现方法
2015/06/09 Python
python相似模块用例
2016/03/04 Python
Python 通过URL打开图片实例详解
2017/06/01 Python
解决PyCharm不运行脚本,而是运行单元测试的问题
2019/01/17 Python
对python函数签名的方法详解
2019/01/22 Python
python对绑定事件的鼠标、按键的判断实例
2019/07/17 Python
python3.6生成器yield用法实例分析
2019/08/23 Python
新建文件时Pycharm中自动设置头部模板信息的方法
2020/04/17 Python
python中二分查找法的实现方法
2020/12/06 Python
使用Python webdriver图书馆抢座自动预约的正确方法
2021/03/04 Python
巴西Mr. Cat在线商店:购买包包和鞋子
2019/09/08 全球购物
印度第一网上礼品店:IGP.com
2020/02/06 全球购物
The North Face官方旗舰店:美国著名户外品牌
2020/09/28 全球购物
当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?
2014/09/09 面试题
mysql如何配置白名单访问
2021/06/30 MySQL