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 相关文章推荐
学习YUI.Ext 第六天--关于树TreePanel(Part 1)
Mar 10 Javascript
JavaScript获取文本框内选中文本的方法
Feb 20 Javascript
详解Angular的双向数据绑定(MV-VM)
Dec 26 Javascript
Javascript中数组去重与拍平的方法示例
Feb 03 Javascript
Angular多选、全选、批量选择操作实例代码
Mar 10 Javascript
Javascript前端经典的面试题及答案
Mar 14 Javascript
socket.io学习教程之基础介绍(一)
Apr 29 Javascript
详解开发react应用最好用的脚手架 create-react-app
Apr 24 Javascript
Vue页面骨架屏的实现方法
May 22 Javascript
原生JavaScript实现滑动拖动验证的示例代码
Dec 06 Javascript
JS sort方法基于数组对象属性值排序
Jul 10 Javascript
JavaScript常用进制转换及位运算实例解析
Oct 14 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
如何在PHP中使用Oracle数据库(1)
2006/10/09 PHP
php适配器模式介绍
2012/08/14 PHP
thinkphp 字母函数详解T/I/N/D/M/A/R/U
2017/04/03 PHP
PDO::query讲解
2019/01/29 PHP
PHP pthreads v3使用中的一些坑和注意点分析
2020/02/21 PHP
javascript IFrame 强制刷新代码
2009/07/23 Javascript
imgAreaSelect 中文文档帮助说明
2011/10/08 Javascript
jquery简单实现滚动条下拉DIV固定在头部不动
2013/11/25 Javascript
原生javascript实现的分页插件pagenav
2014/08/28 Javascript
javascript常用方法总结
2015/05/14 Javascript
jquery实现根据浏览器窗口大小自动缩放图片的方法
2015/07/17 Javascript
sencha ext js 6 快速入门(必看)
2016/06/01 Javascript
js检测离开或刷新页面时表单数据是否更改的方法
2016/08/02 Javascript
学习Javascript闭包(Closure)知识
2016/08/07 Javascript
JS类的定义与使用方法深入探索
2016/11/26 Javascript
JS+Canvas实现的俄罗斯方块游戏完整实例
2016/12/12 Javascript
详解如何在Vue2中实现组件props双向绑定
2017/03/29 Javascript
Vue+element-ui 实现表格的分页功能示例
2018/08/18 Javascript
vue src动态加载请求获取图片的方法
2018/10/17 Javascript
[03:11]完美世界DOTA2联赛PWL DAY8集锦
2020/11/09 DOTA
Python设计模式之观察者模式实例
2014/04/26 Python
以一个投票程序的实例来讲解Python的Django框架使用
2016/02/18 Python
python爬虫系列Selenium定向爬取虎扑篮球图片详解
2017/11/15 Python
tensorflow训练中出现nan问题的解决
2018/02/10 Python
python和mysql交互操作实例详解【基于pymysql库】
2019/06/04 Python
Django的models中on_delete参数详解
2019/07/16 Python
用Python绘制漫步图实例讲解
2020/02/26 Python
keras中的History对象用法
2020/06/19 Python
深入CSS3 动画效果的总结详解
2013/05/09 HTML / CSS
eDreams意大利:南欧领先的在线旅行社
2018/11/23 全球购物
欧缇丽加拿大官方网站:Caudalie加拿大
2019/07/18 全球购物
内科护士实习自我鉴定
2013/10/17 职场文书
公安机关纪律作风整顿剖析
2014/10/10 职场文书
自我查摆剖析材料
2014/10/11 职场文书
教学反思怎么写
2016/02/24 职场文书
Python 阶乘详解
2021/10/05 Python