背景介绍
由于我们常用的 http 请求一般是基于 XHR 对象的实现或者 fetch 实现, 这种请求操作并不会触发浏览器 url 的变化, 这样虽然也能正常请求数据并渲染到页面, 但是如果用户在当前页面操作了某个 get 请求并得到了某条数据, 想通过链接将当前看到的界面分享给其他人时, 那么此时浏览器 url 并不会变化, 通过链接只能访问到初始化的数据界面, 此时并不能达到理想的效果. 如下图所示:
(单纯使用 Ajax 或者 fetch 实现 get 请求时)
当我们在该页面将列表切换到第二页时, 浏览器 url 并没有变化, 所以将链接复制给其他人打开并不会将列表结果切换到第二页, 而是重新初始化.
我自己是一名从事了多年开发的 web 前端老程序员, 目前辞职在做自己的 Web 前端私人定制课程, 今年年初我花了一个月整理了一份最适合 2019 年学习的 Web 前端学习干货, 各种框架都有整理, 送给每一位前端小伙伴, 想要获取的可以添加我的 Web 前端交流群 600610151, 即可免费获取.
实现过程
通过以上的背景和问题, 我们可以想想可以怎么实现呢? 我的第一个反应就是使用 location API 来实现, 我们可以使用 location.search 来读写浏览器 query 参数:
location.search = '?page=2';
这段代码虽然可以改变浏览器 url, 如下图所示:
但会出现一个性能问题, 就是当我们执行了以上代码后, 整个浏览器都会刷新, 导致我们不想刷新的部分也刷新了, 那我们有办法可以让它局部刷新吗? 答案是必须有.
这里就要引出我们本文的重点: history API.
history API
Windows.history 是一个只读属性, 用来获取 History 对象的引用, History 对象提供了操作浏览器会话历史 (浏览器地址栏中访问的页面, 以及当前页面中通过框架加载的页面) 的接口. html5 引入了 history.pushState() 和 history.replaceState() 方法, 它们分别可以添加和修改历史记录条目.
使用 history.pushState() 可以改变 referrer, 它在用户发送 XMLHttpRequest 请求时在 HTTP 头部使用, 改变 state 后创建的 XMLHttpRequest 对象的 referrer 都会被改变. 因为 referrer 是标识创建 XMLHttpRequest 对象时 this 所代表的 Windows 对象中 document 的 URL.
那么我们就可以使用 pushState 来实现我们的更新浏览器 url 功能了.
pushState() 方法
pushState() 需要三个参数: 一个状态对象, 一个标题 (目前已忽略), 和 (可选的) 一个 URL:
状态对象 - 状态对象 state 是一个 JavaScript 对象, 通过 pushState () 创建新的历史记录条目. 无论什么时候用户导航到新的状态, popstate 事件就会被触发, 且该事件的 state 属性包含该历史记录条目状态对象的副
标题 - Firefox 目前忽略这个参数, 但未来可能会用到. 在此处传一个空字符串应该可以安全的防范未来这个方法的更改. 或者, 你可以为跳转的 state 传递一个短标
URL- 该参数定义了新的历史 URL 记录. 注意, 调用 pushState() 后浏览器并不会立即加载这个 URL, 但可能会在稍后某些情况下加载这个 URL, 比如在用户重新打开浏览器时. 新 URL 不必须为绝对路径. 如果新 URL 是相对路径, 那么它将被作为相对于当前 URL 处理. 新 URL 必须与当前 URL 同源, 否则 pushState() 会抛出一个异常. 该参数是可选的, 缺省为当前 UR
实现
- /**
- * 设置浏览器 url
- * params:queryObj(参数对象)
- */
- function setBrowserUrl(queryObj){
- // stringify 是 queryString 的一个 API, 具体可以查看 node 官网, 也可以自己实现
- var url = `${location.pathname}?${stringify(queryObj)}`
- history.pushState({
- url: url
- }, '', url)
- }
这样我们就可以在请求的同时, 调用 setBrowserUrl 方法来改变浏览器 url 了. 接下来我们就可以监听浏览器 url 的变化, 如果浏览器 url 有需要的请求参数, 那么我们就根据请求参数来请求数据, 没有就初始化页面, 这样当我们查看某条记录或者某个小秘密时, 想把该数据保存下来并分享给被人, 是不是就可以实现了呢?
总结
基于 H5 history 可以实现很多优雅使用的工具, 比如路由, 缓存控件等等.
如果想了解更多 webpack,gulp,CSS3,JavaScript,Node.JS,canvas 等前端知识和实战, 欢迎加入我们一起学习讨论, 共同探索前端的边界.
来源: http://www.jianshu.com/p/f84a3f7cdfdb