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 相关文章推荐
qTip 基于JQuery的Tooltip插件[兼容性好]
Sep 01 Javascript
JavaScript中使用构造器创建对象无需new的情况说明
Mar 01 Javascript
Document.location.href和.replace的区别示例介绍
Mar 04 Javascript
js的[defer]和[async]属性
Nov 24 Javascript
jQuery基本选择器之标签名选择器
Sep 03 Javascript
用headjs来管理和加载js 提高网站加载速度
Nov 29 Javascript
js实现适配不同的屏幕大小
Apr 10 Javascript
微信分享调用jssdk实例
Jun 08 Javascript
Vue2仿淘宝实现省市区三级联动
Apr 15 Javascript
vue组件name的作用小结
May 23 Javascript
Bootstrap-table使用footerFormatter做统计列功能
Sep 07 Javascript
Angular短信模板校验代码
Sep 23 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
2019年漫画销量排行榜:鬼灭登顶 海贼单卷制霸 尾田盛赞鬼灭
2020/03/08 日漫
PHP 生成的XML以FLASH获取为乱码终极解决
2009/08/07 PHP
php使用指定编码导出mysql数据到csv文件的方法
2015/03/31 PHP
PHP生成随机字符串(3种方法)
2015/09/25 PHP
利用PHP扩展Xhprof分析项目性能实践教程
2018/09/05 PHP
JavaScript获取某年某月的最后一天附截图
2014/06/23 Javascript
js如何实现点击标签文字,文字在文本框出现
2015/08/05 Javascript
JavaScript记录光标在编辑器中位置的实现方法
2016/04/22 Javascript
JS仿淘宝搜索框用户输入事件的实现
2017/06/19 Javascript
Vue组件实例间的直接访问实现代码
2017/08/20 Javascript
在 React、Vue项目中使用SVG的方法
2018/02/09 Javascript
使用react实现手机号的数据同步显示功能的示例代码
2018/04/03 Javascript
vue.js使用v-model指令实现的数据双向绑定功能示例
2018/05/22 Javascript
详解VScode编辑器vue环境搭建所遇问题解决方案
2019/04/26 Javascript
JavaScript强制类型转换和隐式类型转换操作示例
2019/05/01 Javascript
Vue项目总结之webpack常规打包优化方案
2019/06/06 Javascript
JS实现的简单tab切换功能完整示例
2019/06/20 Javascript
在Vue.js中使用TypeScript的方法
2020/03/19 Javascript
python之从文件读取数据到list的实例讲解
2018/04/19 Python
python通过配置文件共享全局变量的实例
2019/01/11 Python
Python实现的IP端口扫描工具类示例
2019/02/15 Python
Python可迭代对象操作示例
2019/05/07 Python
解决win7操作系统Python3.7.1安装后启动提示缺少.dll文件问题
2019/07/15 Python
获取Pytorch中间某一层权重或者特征的例子
2019/08/17 Python
Django对接支付宝实现支付宝充值金币功能示例
2019/12/17 Python
浅谈tensorflow模型保存为pb的各种姿势
2020/05/25 Python
Python基于Serializer实现字段验证及序列化
2020/11/04 Python
荣耀商城:HIHONOR
2020/11/03 全球购物
linux面试题参考答案(4)
2013/01/28 面试题
旅行社各个岗位职责
2014/03/15 职场文书
班干部演讲稿
2014/04/24 职场文书
村级环境卫生整治方案
2014/05/04 职场文书
副科竞争上岗演讲稿
2014/05/12 职场文书
毕业实习自我鉴定范文2014
2014/09/26 职场文书
新学期新寄语,献给新生们!
2019/11/15 职场文书
JavaScript如何利用Promise控制并发请求个数
2021/05/14 Javascript