hash 模式
什么是 hash 模式
使用 window.location.hash 属性及窗口的 onhashchange 事件,可以实现监听浏览器地址 hash 值变化,执行相应的 js 切换网页:
- hash 指的是地址中 # 号 以及后面的字符,也称为 散列值 ,hash 也称作锚点,本身是用来做页面跳转定位的,如
http://localhost/index.html#abc
,这里的 #abc 就是 hash;- 散列值 是不会随请求发送到服务器端的,所以改变 hash ,不会重新加载页面;实际项目中地址栏只改变哈希部分,按下回车会向服务器发送请求,这个问题的出现是因为缓存的配置(强缓存,协商缓存),如果不配置任何缓存,地址栏没有任何变化,按下回车也会重新加载页面;
- 监听 hashchange 事件,可以当 散列值 改变时,通过 location.hash 来获取和设置 hash 值,location.hash 值的变化会直接反应到浏览器地址栏;
由于 hash 值变化不会导致浏览器向服务器发出请求,而且 hash 改变会触发 hashchange 事件,浏览器的进后退也能对其进行控制,所以 html5 的 history 出现前,基本都是使用 hash 来实现前端路由的;
操作 hash
// 设置 url 的 hash,会在当前 url 后加上 '#qq'
window.location.hash = 'qq';
// 获取 hash 值,'#qq'
window.location.hash
// 监听 hash 变化,点击浏览器的前进后退会触发
window.addEventListener('hashchange', function(){
// todo
})
触发 hashchange 事件的几种情况
第一种
:浏览器地址栏 散列值 的变化(包括浏览器的前进、后退)会触发 window.location.hash 值的变化,从而触发 onhashchange 事件;
第二种
:当浏览器地址栏中 URL 包含哈希如 http://www.baidu.com/#home ,这时按下输入,浏览器发送 http://www.baidu.com/ 请求至服务器,请求完毕之后设置散列值为 #home,进而触发 onhashchange 事件;
第三种
:当只改变浏览器地址栏 URL 的 哈希 部分,这时按下回车,浏览器不会发送任何请求至服务器,这时发生的只是设置散列值新修改的 哈希值 ,并触发 onhashchange 事件;
第四种
:html 中 a 标签的属性 href 可以设置为页面的元素 ID 如 #top (锚点),当点击该链接时页面跳转至该 id 元素所在区域,同时浏览器自动设置 window.location.hash 属性,地址栏中的 哈希值 也会发生改变,并触发 onhashchange 事件;
history 模式
history 模式的由来
hash 本来是拿来做页面定位的,如果拿来做路由的话,原来的锚点功能就不能用了;
其次 hash 的传参是基于 url 的,如果要传递复杂的数据,会有体积的限制,而 history 模式不仅可以在 url 里放参数,还可以将数据存放在一个特定的对象中;
最重要的一点:如果不想要很丑的 hash ,可以用路由的 history 模式;
history 概述
window.history 属性指向 History 对象,它表示当前窗口的浏览历史,当发生改变时,只会改变页面的路径,不会刷新页面;
History 对象保存了当前窗口访问过的所有页面网址,通过 history.length 可以得出当前窗口一共访问过几个网址;
由于安全原因,浏览器不允许脚本读取这些地址,但是允许在地址之间导航,浏览器工具栏的 前进 和 后退 按钮,其实就是对 History 对象进行操作;
history 的 API 和属性
API、属性 | 描述 |
---|---|
length | 当前窗口访问过的网址数量(包括当前网页) |
state | History 堆栈最上层的状态值 |
back() | 移动到上一个网址,等同于点击浏览器的后退键 |
forward() | 移动到下一个网址,等同于点击浏览器的前进键 |
go(number) | 接受一个整数作为参数,以当前网址为基准,移动到参数指定的网址;默认参数为 0 ,相当于刷新当前页面 |
pushState(object, title, url) | 在历史中添加一条记录,不会触发页面刷新,只是导致 history 对象发生变化,地址栏会有变化 · object:通过 pushState 方法可以将该对象内容传递到新页面中 · title:几乎没有浏览器支持该参数,传一个空字符串比较安全 · url:新的网址,必须与当前页面处在同一个域,不指定的话则为当前的路径,如果设置了跨域网址,则会报错 |
replaceState(object, title, url) | 替换的当前记录,而不是添加一条新的记录 |
popstate 事件
每当 history 对象出现变化时,就会触发 popstate 事件
- 仅仅调用 pushState() 或 replaceState() 方法 ,并不会触发该事件;
- 只有用户点击浏览器倒退按钮和前进按钮,或者使用 JavaScript 调用 History.back()、History.forward()、History.go() 时才会触发;
- 另外,该事件只针对同一个文档,如果浏览历史的切换,导致加载不同的文档,该事件也不会触发;
- 页面 第一次加载 的时候,浏览器不会触发 popstate 事件;
使用的时候,可以为 popstate 事件指定回调函数,回调函数的参数是一个 event 事件对象,它的 state 属性指向当前的 state 对象:
window.addEventListener('popstate', function(e) { // e.state 相当于 history.state console.log(history.state); });
history 模式需要后端支持
history 模式要玩好,还需要后端配置支持,因为应用是个单页客户端应用,仅有一个入口文件就是 index.html,浏览器直接访问 http://oursite.com/index.html 可以正常加载应用,此时在应用上面做操作完全没有问题,因为不会向后端发送请求;
当发生了下面两种情况,后端会因为 url 不匹配而报错:
- 客户 ctrl + F5 刷新页面,或者地址栏按 enter 键重新加载页面,恰好此时页面的 url 不是 http://oursite.com/index.html ;
- 客户不是通过 http://oursite.com/index.html 访问页面,而是通过 http://oursite.com/dashoard 访问页面;
对浏览器和后端来说,history 模式的 url 就是正常的 url,后端会根据匹配规则匹配相应的 api 接口 或者 静态资源 ,因此需要在后端添加一个匹配所有情况的配置,如果 url 匹配不到,就返回 index.html 页面;
API 篇:localStorage、sessionStorage
上一篇