JavaScript不刷新实现浏览器的前进后退功能


Posted in Javascript onNovember 05, 2014

最近在学习backbone,学习理解backbone就要先理解spa,理解spa就要先了解单页面应用是如何做到页面不刷新改变url的。

相较于不同页面的跳转,AJAX可以说大大提高了用户的浏览体验,不用看到页面切换之间的白屏是件很惬意的事情。但是很多早先的AJAX应用是不支持浏览器的前进后退的,这导致了用户不管在网站里浏览到何处,一旦刷新就会立刻回到起初的位置,并且用户也无法通过浏览器的前进后退按钮来实现浏览历史的切换。

对于第一个问题,解决还算容易,只要用cookie或者localStorage来记录应用的状态即可,刷新页面时读取一下这个状态,然后发送相应ajax请求来改变页面即可。但是第二个问题就很麻烦了,先说下现代浏览器的解决方案。

HTML5 解决方案

要了解HTML5如何实现前进后退,就要先了解下history对象和location对象。

history对象

History 对象属性

1.length:返回浏览器历史列表中的URL数量,用户在当前标签每访问一个页面,此数量加1。因为隐私原因,URL具体内容不可见。
2.state:与当前网址相关的对象,只能通过pushState和replaceState添加或修改。我们可以可以用它来存储跟url有关的信息。

History 对象方法

1.history.back()

此方法无参数,触发后会返回前一个浏览的页面,相当于点击了浏览器的后退按钮。

2.history.forward()

此方法无参数,触发后会返回后退前浏览的页面,相当于点击了浏览器的前进按钮。

3.history.go(number)

此方法接受一个整形变量参数,history.go(-1)相当于后退一页,history.go(1)相当于前进一页,history.go(0)会刷新当前页面。

4.history.pushState(state, title, url)

改变url且不刷新页面的关键就是它了,此方法会改变当前页面的location.href并且修改当前的history.state对象,执行后history.length会增加1。此方法接受三个参数,

1.state:当前网址相关的对象。
2.title:页面标题,但是所有浏览器都忽略它,要改变标题还是要用document.title。
3.url:一个与当前页面同域的网址,location.href会变成此值。

5.history.replaceState(state, title, url)

此方法同上,但是它不会改变history.length,只会修改当history.state和location.href。

注意pushState和replaceState第三个参数不可跨域,并且不会触发浏览器的popstate事件和onhashchange事件(chrome33下测试)。

location对象

除了点击前进/后退按钮和history事件,还可以通过location的方法和修改location的属性来改变Url:

location对象的属性(读写):

1.host:域名+端口号
2.hostname:域名
3.port:端口号
4.protocol:协议
5.href:完整路径
6.origin:协议+域名+端口
7.hash:井号 (#) 开始的 URL(hash)
8.pathname:文档路径+文档名
9.search:(?)后面的内容

可以通过改变location.href或location.hash来达到无刷新的目的。

location对象的方法:

1.assign:改变url的值,并且将当前的url添加到历史记录中history.length会增加1。location.assig(‘#' + x)会改变url但是不刷新页面。
2.reload:刷新页面。
3.replace:改变url的值,但是history.length不变。使用方法同assign。

popstate事件

当url改变时,比如用户点击前进/后退按钮,history.go(n)(n不等于0),location.hash = x(x不等于当前的location.hash)都会触发此事件。可以用它来监听url,来实现各种功能。

    window.onpopstate = function(){

        //do sth

    }

onhashchange事件

改变hash值会触发popstate事件,而触发popstate事件不一定会触发onhashchange事件。经过测试:

1.hash改变但是location.pathname不变会触发onhashchange事件,比如history.pushState(”, ”, ‘#abc');
2.hash和location.pathname一起改变则不触发,比如history.pushState(”, ”, ‘a#abc');

老旧浏览器的写法

老旧浏览器也不支持pushState和replaceState,所以通过popstate(事实上也不支持这个方法)监听url变化的路走不通。那么只能通过改变url#后面的内容来达到无刷新,但是它们又不支持onhashchange,所以对url的变化是无动于衷的(除了页面会滚动至页面对应id的位置)。那么只能祭出大招:轮询,起一个setInterval来监听url的值。Like this:

var prevHash = window.location.hash; 

var callback = function(){...}

window.setInterval(function() { 

    if (window.location.hash != prevHash) { 

        prevHash = window.location.hash; 

        callback(prevHash); 

    } 

}, 100);

当然这样写非常非常挫,如果不考虑点击页面带有id的a标签来改变hash的情况,可以利用设计模式来优雅的实现监听url。比如经典的观察者模式,专门用一个类来实现改变hash的功能,然后所有要监听url变化的类(观察者)去订阅这个(被观察者)类。

//改变url的类

function UrlChanger() {

    var _this = this;

    this.observers = [];

    //添加观察者

    this.addObserver = function(obj) {...}

    //删除观察者

    this.deleteObserver = function(obj) {...}

    //通知观察者

    this._notifyObservers = function() {

        var length = _this.observers.length;

        console.log(length)

        for(var i = 0; i < length; i++) {

            _this.observers[i].update();

        }

    }

    //改变url

    this.changeUrl = function(hash) {

        window.location.hash = hash;

    _this._notifyObservers();

    }

}

//监听类

function oneOfObservers() {

    var _this = this;

    this.update = function() {...}

}

//实现

var o1 = new UrlChanger();

var o2 = new oneOfObservers();

o1.addObserver(o2);

o1.changeUrl('fun/arg1/arg2/');

//o2 has do sth...
Javascript 相关文章推荐
由JavaScript中call()方法引发的对面向对象继承机制call的思考
Sep 12 Javascript
图片Slider 带左右按钮的js示例
Aug 30 Javascript
标准的js无缝滚动效果
Aug 30 Javascript
Vue组件BootPage实现简单的分页功能
Sep 12 Javascript
Angular2 多级注入器详解及实例
Oct 30 Javascript
JavaScript中this的用法及this在不同应用场景的作用解析
Apr 13 Javascript
js canvas实现QQ拨打电话特效
May 10 Javascript
JS跳转手机站url的若干注意事项
Oct 18 Javascript
JS计算两个时间相差分钟数的方法示例
Jan 10 Javascript
详解Eslint 配置及规则说明
Sep 10 Javascript
Vue.js实现可排序的表格组件功能示例
Feb 19 Javascript
JavaScript命名空间模式实例详解
Jun 20 Javascript
Javascript检查图片大小不要让大图片撑破页面
Nov 04 #Javascript
node.js开发中使用Node Supervisor实现监测文件修改并自动重启应用
Nov 04 #Javascript
node.js中Socket.IO的进阶使用技巧
Nov 04 #Javascript
node.js中的Socket.IO使用实例
Nov 04 #Javascript
Node.js的特点和应用场景介绍
Nov 04 #Javascript
Node.js中的模块机制学习笔记
Nov 04 #Javascript
Node.js异步I/O学习笔记
Nov 04 #Javascript
You might like
新闻分类录入、显示系统
2006/10/09 PHP
PHP一些常用的正则表达式字符的一些转换
2008/07/29 PHP
访问编码后的中文URL返回404错误的解决方法
2014/08/20 PHP
PHP中如何判断exec函数执行成功?
2016/08/04 PHP
PHP实现二叉树深度优先遍历(前序、中序、后序)和广度优先遍历(层次)实例详解
2018/04/20 PHP
PHP addcslashes()函数讲解
2019/02/03 PHP
javascript replace()正则替换实现代码
2010/02/26 Javascript
CodeMirror2 IE7/IE8 下面未知运行时错误的解决方法
2012/03/29 Javascript
javascript获取xml节点的最大值(实现代码)
2013/12/11 Javascript
理解jQuery stop()方法
2014/11/21 Javascript
JS烟花背景效果实现方法
2015/03/03 Javascript
jQuery实现的自定义弹出层效果实例详解
2016/09/04 Javascript
nodejs模块nodemailer基本使用-邮件发送示例(支持附件)
2017/03/28 NodeJs
微信小程序实现选项卡功能
2020/06/19 Javascript
原生javascript AJAX 三级联动的实现代码
2018/05/04 Javascript
vue.js层叠轮播效果的实例代码
2018/11/08 Javascript
使用axios发送post请求,将JSON数据改为form类型的示例
2019/10/31 Javascript
有关vue 开发钉钉 H5 微应用 dd.ready() 不执行问题及快速解决方案
2020/05/09 Javascript
[03:30]完美盛典趣味短片 CSGO2019年度名场面
2019/12/07 DOTA
详解Python编程中对Monkey Patch猴子补丁开发方式的运用
2016/05/27 Python
Python编程之基于概率论的分类方法:朴素贝叶斯
2017/11/11 Python
python 2.7 检测一个网页是否能正常访问的方法
2018/12/26 Python
Python中正反斜杠(‘/’和‘\’)的意义与用法
2019/08/12 Python
pytorch 固定部分参数训练的方法
2019/08/17 Python
python2与python3爬虫中get与post对比解析
2019/09/18 Python
python3 tkinter实现添加图片和文本
2019/11/26 Python
基于python监控程序是否关闭
2020/01/14 Python
django实现模型字段动态choice的操作
2020/04/01 Python
Python使用os.listdir和os.walk获取文件路径
2020/05/21 Python
联想台湾官网:Lenovo TW
2018/05/09 全球购物
硅酸盐工业控制专业应届生求职信
2013/11/02 职场文书
工会经费申请报告
2015/05/15 职场文书
医学会议开幕词
2016/03/03 职场文书
导游词之河北滦平金山岭长城
2019/10/16 职场文书
创作书写之导游词实用技巧分享(干货)
2019/12/20 职场文书
SQL Server数据定义——模式与基本表操作
2021/04/05 SQL Server