前端路由的两种实现原理

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/538813.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

3.JDK和JRE和JVM的区别

JDK --Java Development Kit --java 开发工具包 JRE --Java Runtime Environment --java运行时环境 JVM --Java Virtual Machine --java虚拟机 ------------- 更多的Java&#xff0c;Angular&#xff0c;Android&#xff0c;大数据&#xff0c;J2EE&#xff0c;Python…

缓存cache

由于Django是动态网站&#xff0c;所有每次请求均会去数据进行相应的操作&#xff0c;当程序访问量大时&#xff0c;耗时必然会更加明显&#xff0c;最简单解决方式是使用&#xff1a;缓存&#xff0c;缓存将一个某个views的返回值保存至内存或者memcache中&#xff0c;5分钟内…

4.JVM简述

JVM是一种规范。 就是一个虚拟的用于执行bytecodes字节码的计算机 可以用软件来实现&#xff0c;如IBM,SUN,BEA等按照这个规范实现&#xff0c;可以实现比SUN公司更好的JVM&#xff0c;我们自己也可以实现一个。 可以使用硬件来实现&#xff0c;如sun与intel公司研发java的芯…

5.JDK环境配置

下载 进入Oracle官网下载&#xff0c;点击进入 安装 一路下一步。记住安装到哪里了。 配置环境变量 JAVA_HOME 刚才的java安装目录 PATH %JAVA_HOME%\bin PATH里配置多个用英文的分号; 分隔。 *classpath&#xff0c;jdk5.0以上可以不用配置了 测试 windows下&#xf…

6.第一个程序Hello World

新建文件夹 在C盘新建个文件夹 mycode。注意不要用中文。 新建java文件 1、显示隐藏文件名。 2、右键新建文本文件 3、重命名为 Welcome.java。&#xff08;首字母必须大写。如果不显示隐藏文件名&#xff0c;会是Welcome.java.txt不是java文件&#xff09; 4、编写代码 p…

pythonstdin_python 笔试输入:sys.stdin.readline和input

①&#xff1a;输入一行数据并输 出两种方法 # 输入一行数据并输出 import sys # 方法一&#xff1a; str1 input() print(input 输入:,str1,len,len(str1)) print(循环遍历输入得到输入的每个字符的ascii码如下&#xff1a;) for i in str1: print(ord(i)) # 方法二&#xff…

8.对Hello World程序的深入

Welcome.java public class Welcome{public static void main(String[] args){System.out.println("Hello World,I am Java!");}}1、Java对大小写敏感。如果出现了大小写拼写错误&#xff0c;程序无法运行。 关键字class表明Java程序中的全部内容都包含在类中&…

python整数类型没有取值范围限制_详解Python中6种数据类型

Python中数据类型主要有六种&#xff1a;数字类型&#xff0c;字符串类型&#xff0c;元组类型&#xff0c;列表类型&#xff0c;文件类型和字典类型&#xff0c;我们今天先介绍前四种类型。 假如在Python程序中&#xff0c;出现了“010”&#xff0c;那么这个“010”到底是什么…

python爬虫的用途_python爬虫用途

广告关闭 腾讯云11.11云上盛惠 &#xff0c;精选热门产品助力上云&#xff0c;云服务器首年88元起&#xff0c;买的越多返的越多&#xff0c;最高返5000元&#xff01;专业点来说就是应用多台机器同时实现爬虫任务&#xff0c;这多台机器上的爬虫&#xff0c;就是称作分布式爬虫…

二元函数泰勒公式例题_高等数学期末总复习 DAY 5. 罗尔定理证明题 拉格朗日、柯西中值定理 泰勒公式及麦克劳林公式...

DAY 5.DAY 5.1.罗尔定理2.拉格朗日定理3.柯西中值定理4.泰勒公式及麦克劳林公式1.罗尔定理罗尔定理描述如下&#xff1a;如果 R 上的函数 f(x) 满足以下条件&#xff1a;&#xff08;1&#xff09;在闭区间 [a,b] 上连续&#xff0c;&#xff08;2&#xff09;在开区间 (a,b) 内…

android应用程序是什么,简述Android应用程序结构是什么?公共题库

试题分类&#xff1a;Android简述Android应用程序结构是什么?解析:Android应用程序结构是&#xff1a;LinuxKernel(Linux内核)、Libraries(系统运行库或者是c/c核心库)、ApplicationFramework(开发框架包)、Applications(核心应用程序)以下这些控件可以放置按钮&#xff1f;答…

《程序设计与数据结构》第八周学习总结

学号 20172326 《程序设计与数据结构》第八周学习总结 教材学习内容总结 后绑定在程序执行时执行多态性可由继承与接口实现排序有选择法排序与插入法排序搜索分为线性搜索与二分搜索算法&#xff0c;同一类型的不同方法可能解决同一问题&#xff0c;但是&#xff0c;效率与难以…

python获取文件名不含后缀名_大部分Python资料都没有说到的重点-用实战教你解决问题的思路...

前言最近有些刚入门Python的小伙伴问我&#xff0c;他已经学会了大部分语法&#xff0c;基本的列表&#xff0c;元组也会使用&#xff0c;但是在实际中需要做一点小需求的时候&#xff0c;仍然不知所措。解决问题重要的并非是如何写代码&#xff0c;而是如何分析和拆解问题&…

12.JAVA基本数据类型

Java是一种强类型语言&#xff0c;每个变量都必须声明类型。 String 不是java的基本数据类型&#xff01;&#xff01;&#xff01; 除了8种基本数据类型之外&#xff0c;其他的都是引用类型。 引用类型的初始值是null byte&#xff0c;short&#xff0c;int类型的默认值为0 …

opencv android jni,OpenCV - AndroidStudio的JNI工程及引用OpenCV

一把利刃&#xff0c;用不好&#xff0c;会伤到你遍体鳞伤。用得好&#xff0c;便为你披荆斩棘&#xff0c;所向披靡。好与不好之间&#xff0c;便是历练。几经波折&#xff0c;终于跌跌撞撞,集成了OpenCV,并实现了灰度图片&#xff0c;自此一扇新的大门已经打开。至此我手中已…

excel图表交互联动_深入讲解EasyShu图表与引用数据动态联动功能

EasyShu一开始的架构是将制作好的图表最终返回给用户&#xff0c;不依赖用户工作表的单元格区域引用&#xff0c;可满足图表绘制后的脱离数据源分享传播&#xff0c;无奈用户最强烈的反馈是要求图表与数据保持联动&#xff0c;这一需求实在对EasyShu是一个巨大的挑战。为了将Ea…

android代码生成excel,AndroidExcel

Android_Excel在android中生成excel##效果图##初始化数据首先我们要先造下测试数据&#xff0c;这里我把数据写死在一个常量类Const中&#xff0c;如下&#xff1a;public class Const {public interface OrderInfo{public static final String[][] orderOne new String[][] {…

14.JAVA整型变量

表示形式 Java语言整型常数的3种表示形式&#xff1a; 1、十进制整数&#xff1a;99&#xff0c;-100,0 2、八进制整数&#xff1a;要以0开头&#xff0c;如015 3、十六进制整数&#xff1a;以0x开头&#xff0c;如0x15 点击查看十进制八进制十六进制概念 public static v…

exists sql用法_干货!SQL性能优化,书写高质量SQL语句

写SQL语句的时候我们往往关注的是SQL的执行结果&#xff0c;但是是否真的关注了SQL的执行效率&#xff0c;是否注意了SQL的写法规范&#xff1f;以下的干货分享是在实际开发过程中总结的&#xff0c;希望对大家有所帮助&#xff01;1. limit分页优化当偏移量特别大时&#xff0…

eureka server配置_springcloud项目搭建第三节:eureka集群

在上一节搭建的项目基础上&#xff0c;在创建一个eureka-server-two的子项目和eureka-server项目一样&#xff0c;然后修改各自项目的application.yml文件eureka-server项目的application.yml文件修改2点1.修改eureka的注册地址改成另一个eureka-server-two项目的注册中心地址2…