一、路由
1.路由定义
在现代前端开发中,路由是非常重要的一环。但路由到底是什么呢?
- 路由就是指随着浏览器地址栏的变化,展示给用户的页面也不相同。
- 路由就是
URL
到函数的映射。这是从路由的实现原理上来解释路由是什么的。
2.路由的发展
在单页应用
并没有普及时,后端路由
担任着比较大的作用。
后端路由又可称之为
服务器端路由
,因为对于服务器来说,当接收到客户端发来的HTTP请求
,就会根据所请求的相应URL
,来找到相应的映射函数,然后执行该函数,并将函数的返回值发送给客户端。对于最简单的静态资源服务器,可以认为,所有URL的映射函数就是一个文件读取操作。对于动态资源,映射函数可能是一个数据库读取操作,也可能是进行一些数据的处理,等等。然后根据这些读取的数据,在服务器端就使用相应的模板来对页面进行渲染后,再返回渲染完毕的页面。
- 好处:安全性好,
SEO
好。 - 缺点:
加大服务器的压力,不利于用户体验,代码冗合
。
此篇文章重在前端理由实现,那么后端路由暂时就说这么多。对于前端路由来说,路由的映射函数通常是进行一些DOM
的显示和隐藏操作。这样,当访问不同的路径的时候,会显示不同的页面组件。前端路由主要有以下两种实现方案:
hash
history API
二、前端路由实现原理
1.通过location.hash实现前端路由
hash
就是一个url
中#
后面的部分,也叫做url的锚部分
,锚部分在服务器端会被自动忽略,但是在浏览器中是可以通过loaction.hash
来获取的。通过hash
方法实现前端路由主要是用到的是onhashchange
事件,这个事件可以实时监听url
中hash
值的变化,由此来根据hash
值的变化进行一些DOM
的切换操作。
//html中
<element onhashchange="myScript">
//javascript中
object.onhashchange=function(){myScript};
//Javascript中,使用addEventListener()方法:
object.addEventListener("hashchange", myScript);
1. onhashchange
事件的触发条件:
1.改变
url
地址,在最后面增加或改变其hash
值。
2.改变
location.href
或location.hash
的值。
3.点击带有锚点的链接。
4.浏览器前进后退可能导致
hash
的变化,前提是两个网页地址中的hash
值不同。
2. 利用Hash
实现前端路由:
当浏览器地址栏
url
的hash
值发生变化时,就会触发onhashchange
事件,这时通过window.location.hash
可以拿到当前浏览器的url
的hash
值,注意此时的hash
值是带有#
的,因此需要对其值进行相应的处理,去掉#
,并且如果当前url
不含hash
值的话,就将其当做根目录处理。之后将url
和相应的组件函数进行映射,根据不同的hash
值执行不同的回调函数,也就是加载相应的组件。
2.通过window.history
和popstate
实现前端路由
1.history
对象介绍
浏览器窗口会为用户提供一个history
对象,用来保存用户操作页面的历史,我们在浏览网页时的前进后退操作都是基于这个对象来实现的。在前端路由的实现过程中主要用到了history
对象里的history.pushState()
和history.replaceState()
这两个接口。
history.replaceState(dataObj,title,url);
history.pushState(dataObj,title,url);
pushState()
和replaceState()
方法很类似,二者均接受三个参数,分别是state、title和url。
state
:用来存放将要插入的history
实体的相关信息,它是一个json
格式的参数。- 传入
history
实体的标题,需要注意的是firefox现在会自动忽略掉这个参数。 - 用来传递新的
history
实体的相对路径,如果其值为null
则表示当前要插入的history
实体与前一个实体一致,没有改变。
2.replaceState()
方法与pushState()
方法的唯一区别
replaceState()
方法会将最新一条的history
实体覆盖掉,而不是直接添加,这种情况在处理例如登录页面这些不需要记录到history
中的情况时非常有用。
这里需要注意的是
history
提供的这两个方法不会主动出发浏览器页面的刷新,只是history
对象包括地址栏的内容会发生改变,当出发前进后退等history
事件时才会进行相应的响应。另外,作为参数传入的url
也会受到同源策略的限制,如果出现跨域等情况会导致报错。
3. popstate
是官方提供的事件,当history
中的记录发生改变时就会触发该事件。
4. 利用history
实现前端路由:
当想要跳转到指定
url
的时候,将目标url
通过pushState()
或者replaceState()
方法填入到history
和地址栏中,此时由于上述两种方法不会主动进行页面刷新,因此页面仍停留在当前页面,只是url地址发生了改变。之后通过popstate
事件响应,执行相应的回调函数,实现前端组件间的切换。
三、前端路由的优势
- 页面刷新速度快。由于后端路由在请求一个新路径时,会重新向服务器发送请求,之后再根据服务器的相应结果重新渲染页面,这个过程会受到网络延迟的影响,而前端路由省略了整个请求过程,只是完成部分组件间的切换,因此页面的刷新速度会相对较快,用户体验相对较好。
- 复用性强。使用前端路由,代码中的layout、css、js都可以共用,以此来减少重复加载,提供程序性能。
- 页面状态可记录。不使用前端路由,仅通过ajax进行页面局部切换的单页应用,由于url始终保持不变,因此页面的状态是无法记录的,而前端路由很好的解决了这个问题。
四、React-Router和React-Router-Dom路由实现
1.环境搭建
你可以使用create-react-app
搭建,也可以自己搭建一个最简单的开发环境。在入口页面我们写上最简单的不掺和路由的方法。
import React from 'react';
import ReactDom from 'react-dom';
ReactDom.render(<div>ReactDom</div>,document.getElementById("root"));
浏览器效果为:
2.React-Router
、React-Router-Dom
介绍
1.React-Router
和React-Router-Dom
区别
通常我们会看到以下写法
import {Switch, Route, Router} from 'react-router';
import {HashHistory, Link} from 'react-router-dom';
还有另外一种写法
import {Swtich, Route, Router, HashHistory, Link} from 'react-router-dom';
react-router
: 实现了路由的核心功能。
react-router-dom
: 基于react-router
,加入了在浏览器运行环境下的一些功能,例如:Link组件,会渲染一个a标签。BrowserRouter
和HashRouter
组件,前者使用pushState
和popState
事件构建路由,后者使用window.location.hash
和hashchange
事件构建路由。
我们看下React-Router-Dom
实现的Switch
// Written in this round about way for babel-transform-imports
import { Switch } from 'react-router'
export default Switch
只是从react-router
中导入Switch组件,然后重新导出而已。
Router、Route也是如此。
react-router-dom
依赖react-router
,所以我们使用npm安装依赖的时候,只需要安装相应环境下的库即可,不用再显式安装react-router
。基于浏览器环境的开发,只需要安装react-router-dom
。