2019独角兽企业重金招聘Python工程师标准>>>

History API

这里不细说每一个 API 的用法,大家可以看 MDN 的文档:https://developer.mozilla.org...

重点说其中的两个新增的API history.pushState 和 history.replaceState

这两个 API 都接收三个参数,分别是

  • 状态对象(state object) — 一个JavaScript对象,与用pushState()方法创建的新历史记录条目关联。无论何时用户导航到新创建的状态,popstate事件都会被触发,并且事件对象的state属性都包含历史记录条目的状态对象的拷贝。

  • 标题(title) — FireFox浏览器目前会忽略该参数,虽然以后可能会用上。考虑到未来可能会对该方法进行修改,传一个空字符串会比较安全。或者,你也可以传入一个简短的标题,标明将要进入的状态。

  • 地址(URL) — 新的历史记录条目的地址。浏览器不会在调用pushState()方法后加载该地址,但之后,可能会试图加载,例如用户重启浏览器。新的URL不一定是绝对路径;如果是相对路径,它将以当前URL为基准;传入的URL与当前URL应该是同源的,否则,pushState()会抛出异常。该参数是可选的;不指定的话则为文档当前URL。

相同之处是两个 API 都会操作浏览器的历史记录,而不会引起页面的刷新。

不同之处在于,pushState会增加一条新的历史记录,而replaceState则会替换当前的历史记录。

我们拿大百度的控制台举例子(具体说是我的浏览器在百度首页打开控制台。。。)

我们在控制台输入

window.history.pushState(null, null, "https://www.baidu.com/?name=orange");

好,我们观察此时的 url 变成了这样

我们这里不一一测试,直接给出其它用法,大家自行尝试

window.history.pushState(null, null, "https://www.baidu.com/name/orange");
//url: https://www.baidu.com/name/orangewindow.history.pushState(null, null, "?name=orange");
//url: https://www.baidu.com?name=orangewindow.history.pushState(null, null, "name=orange");
//url: https://www.baidu.com/name=orangewindow.history.pushState(null, null, "/name/orange");
//url: https://www.baidu.com/name/orangewindow.history.pushState(null, null, "name/orange");
//url: https://www.baidu.com/name/orange

注意:这里的 url 不支持跨域,当我们把 www.baidu.com 换成 baidu.com 时就会报错。

Uncaught DOMException: Failed to execute 'pushState' on 'History': A history state object with URL 'https://baidu.com/?name=orange' cannot be created in a document with origin 'https://www.baidu.com' and URL 'https://www.baidu.com/?name=orange'.

回到上面例子中,每次改变 url 页面并没有刷新,同样根据上文所述,浏览器会产生历史记录

这就是实现页面无刷新情况下改变 url 的前提,下面我们说下第一个参数 状态对象

如果运行 history.pushState() 方法,历史栈对应的纪录就会存入 状态对象,我们可以随时主动调用历史条目

此处引用 mozilla 的例子

<!DOCTYPE HTML>
<!-- this starts off as http://example.com/line?x=5 -->
<title>Line Game - 5</title>
<p>You are at coordinate <span id="coord">5</span> on the line.</p>
<p><a href="?x=6" onclick="go(1); return false;">Advance to 6</a> or<a href="?x=4" onclick="go(-1); return false;">retreat to 4</a>?
</p>
<script>var currentPage = 5; // prefilled by server!!!!function go(d) {setupPage(currentPage + d);history.pushState(currentPage, document.title, '?x=' + currentPage);}onpopstate = function(event) {setupPage(event.state);}function setupPage(page) {currentPage = page;document.title = 'Line Game - ' + currentPage;document.getElementById('coord').textContent = currentPage;document.links[0].href = '?x=' + (currentPage+1);document.links[0].textContent = 'Advance to ' + (currentPage+1);document.links[1].href = '?x=' + (currentPage-1);document.links[1].textContent = 'retreat to ' + (currentPage-1);}
</script>

我们点击 Advance to ? 对应的 url 与模版都会 +1,反之点击 retreat to ? 就会都 -1,这就满足了 url 与模版视图同时变化的需求

实际当中我们不需要去模拟 onpopstate 事件,官方文档提供了 popstate 事件,当我们在历史记录中切换时就会产生 popstate 事件。对于触发 popstate 事件的方式,各浏览器实现也有差异,我们可以根据不同浏览器做兼容处理。

hash

我们经常在 url 中看到 #,这个 # 有两种情况,一个是我们所谓的锚点,比如典型的回到顶部按钮原理、Github 上各个标题之间的跳转等,路由里的 # 不叫锚点,我们称之为 hash,大型框架的路由系统大多都是哈希实现的。

同样我们需要一个根据监听哈希变化触发的事件 —— hashchange 事件

我们用 window.location 处理哈希的改变时不会重新渲染页面,而是当作新页面加到历史记录中,这样我们跳转页面就可以在 hashchange 事件中注册 ajax 从而改变页面内容。

这里我在 codepen 上模拟了一下原理: http://codepen.io/orangexc/pe...点击预览

hashchange 在低版本 IE 需要通过轮询监听 url 变化来实现,我们可以模拟如下

(function(window) {// 如果浏览器不支持原生实现的事件,则开始模拟,否则退出。if ( "onhashchange" in window.document.body ) { return; }var location = window.location,oldURL = location.href,oldHash = location.hash;// 每隔100ms检查hash是否发生变化setInterval(function() {var newURL = location.href,newHash = location.hash;// hash发生变化且全局注册有onhashchange方法(这个名字是为了和模拟的事件名保持统一);if ( newHash != oldHash && typeof window.onhashchange === "function"  ) {// 执行方法window.onhashchange({type: "hashchange",oldURL: oldURL,newURL: newURL});oldURL = newURL;oldHash = newHash;}}, 100);
})(window);

大型框架的路由当然不会这么简单,angular 1.x 的路由对哈希、模版、处理器进行关联,大致如下

app.config(['$routeProvider', '$locationProvider', function ($routeProvider, $locationProvider) {$routeProvider.when('/article', {templateUrl: '/article.html',controller: 'ArticleController'}).otherwise({redirectTo: '/index'});$locationProvider.html5Mode(true);
}])

这套路由方案默认是以 # 开头的哈希方式,如果不考虑低版本浏览器,就可以直接调用 $locationProvider.html5Mode(true) 利用 H5 的方案而不用哈希方案。

总结

两种方案我推荐 hash 方案,因为照顾到低级浏览器,就是不美观(多了一个 #),两者兼顾也不是不可,只能判断浏览器给出对应方案啦,不过也只支持 IE8+,更低版本兼容见上文!

这个链接的 demo 含有判断方法:http://sandbox.runjs.cn/show/... 。同时给出 Github 仓库地址: minrouter,推荐大家读下源码,仅仅 117 行,精辟!

如果在上面链接测试时你的 url 里多了一个 #,说明你的浏览器该更新啦。

文章出自 orange 的 个人博客 http://orangexc.xyz/

转载于:https://my.oschina.net/ZhenyuanLiu/blog/1802350

前端路由的两种实现原理相关推荐

  1. c语言实现路由功能,前端路由的两种实现方式,内附详细代码

    一.前端路由介绍 前端路由主要应用在SPA(单页面开发)项目中.在无刷新的情况下,根据不同的URL来显示不同的组件或者内容. 前端路由的实现原理 : hash值 + onhashchange事件 hi ...

  2. 前端路由的两种模式:hashhistory

    前端路由的两种模式:hash和history 1.hash hash模式是通过onhashchange事件,监听url的修改优点:兼容性比较高,可以直接在项目部署上线时使用缺点:url中带#号,不美观 ...

  3. js文件里获取路由 vue_【源码拾遗】从vue-router看前端路由的两种实现

    本文由浅入深观摩vue-router源码是如何通过hash与History interface两种方式实现前端路由,介绍了相关原理,并对比了两种方式的优缺点与注意事项.最后分析了如何实现可以直接从文件 ...

  4. Vue-Router前端路由的两种模式、区别、原理?

    vue路由有⼏种模式?有什么区别?原理是什么? 一.vue路由有几种模式? 二.两者区别 三.原理 一.vue路由有几种模式? vue的路由模式⼀共有两种,分别是哈希和history 二.两者区别 哈 ...

  5. vue-router前端路由的两种模式的区别

    一.前端路由存在的意义 前端路由主要应用在spa项目中. 核心---在无刷新(不向后端发送请求)的情况下,可以根据不同url更改视图. 二.浏览器提供hash 和history 两种模式支持(可以说, ...

  6. 【知识梳理】前端路由的两种模式

    一.概述 这是几年前写的的一篇文章,发在了简书上面,现在看来仍然有一些不足,所以再次整理一下发在掘金. 二.什么是单页面应用(SPA)? 首先我们需要了解一下前置的基础知识----SPA(单页面应用) ...

  7. 前端常见问题以及处理方式 - - - (二)前端路由的两种模式和区别

    提示:前端查漏补缺,仅代表个人观点,不接受如何批评 文章目录 一.前端路由实现了什么? 二.hash模式 1.介绍 2.特点 三.history模式 1.介绍 2.特点 3.history存在问题 三 ...

  8. vue路由的两种模式:hash与history的区别

    前言:众所周知,vue-router有两种模式,hash模式和history模式,下面来看看两者的区别. 一.基本情况 直观区别:hash模式url带#号,history模式不带#号. 1.hash模 ...

  9. vue路由之路由的两种模式

    文章目录 简介 hash路由 history模式 两种模式的比较 history存在的问题 专栏目录请点击 简介 一般路由分两种形式 一种是哈希路由,最明显的特征就是路由中有一个# 还有一种就是his ...

最新文章

  1. 2.4g 无线键鼠对码软件_富德iK8900无线键鼠套装评测:静音纤薄
  2. 最新组合式模型量化方法,实现FPGA最高硬件利用率,准确率-推理速度达到SOTA...
  3. 洛谷 1359 租用游艇
  4. Linux下paste命令详解
  5. 手机两列布局,正方形
  6. Ubuntu16.04以root身份登入!
  7. 洛谷——P1478 陶陶摘苹果(升级版)
  8. 第一部分 走进Java
  9. win11错误代码0xc1900101怎么解决 windows11错误代码0xc1900101的解决方法
  10. 合规不利于安全的五种情形
  11. 公司邮箱通讯录的更新
  12. PS批处理生成EXE格式
  13. java word jar包_java操作word书签生成word模板不用jar包
  14. linux 服务器远程开机,Linux 下实现远程开机
  15. .net rar zip压缩包解压
  16. java毕业设计二次元信息分享平台(附源码、数据库)
  17. 基于Master-DistributedMaster-Slave架构的replication
  18. 投资理财之基金一、初识基金
  19. STM32 系统配置的时钟获取方式
  20. 安卓自定义View画钟实现转动

热门文章

  1. php怎么把日期加时间,将小时分钟添加到日期时间 - php
  2. 20199计算机二级java答案_计算机二级Java练习题-2019.9
  3. java返回特定下标元素_java基础--输出数组中指定元素的下标
  4. 绿盟科技鸿蒙系统,华为 X 绿盟科技,打造“云原生安全新生态”
  5. elementui 上传七牛_element ui使用上传组件上传文件到七牛(qiniu-js)
  6. android 移除fragment,Android Viewpager+Fragment取消预加载及Fragment方法的学习
  7. 计算机控制系统笔记,笔记型计算机的电源控制系统
  8. html5中的css特性,浅谈HTML5 CSS3的新交互特性
  9. 机器人无限火力无限e符文_LOL:无限火力开黑指南 三大玩法让你快乐加倍
  10. linux内核 默认路由表,[Linux] linux路由表-Go语言中文社区