React 路由概念详解
Posted YuLong~W
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React 路由概念详解相关的知识,希望对你有一定的参考价值。
路由的理解
路由:
简单的说,路由是根据不同的 url 地址展示不同的内容或页面
- 一个路由就是一个映射关系(key:value)
- key为 路径,value可能是 function 或 component
路由分类:
- 后端路由:
- 用户请求的url导航到具体的html页面;每跳转到不同的URL,都是重新访问服务端,然后服务端返回页面,页面也可以是服务端获取数据,然后和模板组合,返回HTML,也可以是直接返回模板HTML,然后由前端js再去请求数据,使用前端模板和数据进行组合,生成想要的HTML。
- 理解: value是 function,用来处理客户端提交的请求。
- 注册路由:
router.get(path, function(req, res))
- 工作过程:当node接收到一个请求时,根据请求路径找到匹配的路由,调用路由中的函数来处理请求,返回响应数据
- 前端路由:
- 把不同路由对应不同的内容或页面的任务交给前端来做,之前是通过服务端根据 url 的不同返回不同的页面实现的
- 浏览器端路由,value是 component,用于展示页面内容。
- 注册路由:
<Route path="/test" component={Test}>
- 工作过程:当浏览器的path变为 /test时,当前路由组件就会变为Test组件
前端路由优点:
1、从性能和用户体验的层面来比较的话,后端路由每次访问一个新页面的时候都要向服务器发送请求,然后服务器再响应请求,这个过程肯定会有延迟。而前端路由在访问一个新页面的时候仅仅是变换了一下路径而已,没有了网络延迟,对于用户体验来说会有相当大的提升。
2、在某些场合中,用ajax请求,可以让页面无刷新,页面变了但url没有变化,用户就不能复制到想要的地址,用前端路由做单页面网页就很好的解决了这个问题。
前端路由缺点:
使用浏览器的前进,后退键的时候会重新发送请求,没有合理地利用缓存。
前端路由
随着 ajax 的使用越来越广泛,前端的页面逻辑开始变得越来越复杂,特别是单页Web应用(Single Page Web Application,SPA))的兴起,前端路由系统随之开始流行。
SPA的理解:
- 单页Web应用(single page web application,SPA)
- 整个应用只有一个完整的页面
- 点击页面中的链接不会刷新页面,只会做页面的 局部更新
- 数据都需要通过ajax请求获取, 并在前端异步展现
1、从用户的角度看,前端路由主要实现了两个功能(使用ajax更新页面状态的情况下):
- 记录当前页面的状态(保存或分享当前页的url,再次打开该url时,网页还是保存(分享)时的状态)
- 可以使用浏览器的前进后退功能(如点击后退按钮,可以使页面回到使用ajax更新页面之前的状态,url也回到之前的状态)
2、作为开发者,要实现这两个功能,需要做到:
- 改变url且不让浏览器向服务器发出请求
- 监测 url 的变化
- 截获 url 地址,并解析出需要的信息来匹配路由规则
以下为两种模式实现前端路由:
hash模式
这里的 hash 就是指 url 尾巴后的 # 号以及后面的字符。这里的 # 和 css 里的 # 是一个意思。hash也称作锚点,本身是用来做页面定位的,可以使对应 id 的元素显示在可视区域内。
由于 hash 值变化不会导致浏览器向服务器发出请求,因此不会刷新页面,从而实现无刷新的效果。所以在 html5 的 history 出现前,基本都是使用 hash 来实现前端路由。
1、hash属性: 在当前页面中,可以通过:window.location.hash = 'edit'
来实现改变当前 url 的hash值,执行上述的hash赋值,页面的url发生改变。
例如:赋值前:http://localhost:3000 赋值后:http://localhost:3000 /#edit
2、hashchange 事件: hash 改变会触发 hashchange 事件,浏览器的进后退也能对其进行控制。有了监听事件,且改变hash页面不刷新,这样就可以在监听事件的回调函数中,执行我们展示和隐藏不同UI显示的功能,从而实现前端路由。
window.addEventListener('hashchange', function(){
// 监听hash变化,点击浏览器的前进后退会触发
})
此外,要改变页面的hash值,还可以通过 html的 <a> 标签
来实现页面跳转:<a href="#edit"></a>
hash 的缺点:
- 搜索引擎对带有hash的页面不友好
- 带有hash的页面难以追踪用户的行为
history模式
已经有 hash 模式了,而且 hash 能兼容到IE8, history 只能兼容到 IE10,为什么还要搞个 history 呢?
原因:
1、hash 本来是拿来做页面定位的,如果拿来做路由的话,原来的锚点功能就不能用了。
2、hash 的传参是基于 url的,如果要传递复杂的数据,会有体积的限制,而history 模式不仅可以在url里放参数,还可以将数据存放在一个特定的对象中。
相关API:
history的属性:
- length:返回在会话历史有多少条记录,包含了当前会话页面。如果打开了一个新的tab,那么这个length会加1
- state:保存了popState等事件方法,所传递过来的属性和对象(后面会在pushState和replaceState方法中详细的介绍)
history的方法:
- history.back():返回浏览器会话历史中的上一页,跟浏览器的 回退 按钮功能相同
- history.forword():指向浏览器会话历史中的下一页,跟浏览器的 前进 按钮相同
- history.go(n):可以跳转到浏览器会话历史中的 指定的某一个记录页,n可为正数或者负数
- history.pushState(state, title, url):pushState可以 将给定的数据压入到浏览器会话历史栈中,该方法接受3个参数,对象,title,和一串url,值得注意的是,pushState调用后会改变页面的url,但是不会刷新页面
- state:需要保存的数据,这个数据在触发popstate事件时,可以在event.state里获取
- title:标题,基本没用,一般传 null
- url:设定新的历史记录的 url。新的 url 与当前 url 的 origin 必须是一樣的,否则会抛出错误。url可以是绝对路径,也可以是相对路径。
- 例如: 当前url是 https://www.baidu.com/a/,执行
history.pushState(null, null, './qq/')
,则变成 https://www.baidu.com/a/qq/,执行history.pushState(null, null, '/qq/')
,则变成 https://www.baidu.com/qq/
- history.replaceState(state, title, url):replaceState 将当前的会话页面的url替换成指定的数据,replaceState后也会改变当前页面的url,但是也不会刷新页面。
pushState和replaceState的不同点:前者是压入浏览器的会话历史栈中,使得History.length加1,而后者是替换当前的这条会话历史,因此不会增加History.length
history的优点:
- 对搜索引擎友好
- 方便统计用户行为
缺点:
- 兼容性不如hash
- 需要后端做相应的配置,否则访问子页面回出现404错误。
react-router-dom
React实现页面路由的模块:react-router-dom
- react的一个插件库
- 专门用来实现一个SPA应用
- 基于react的项目基本都会用到此库
路由的基本使用
下载react-router-dom: npm install react-router-dom
- 1.明确好界面中的导航区、展示区
- 2.导航区的a标签改为Link标签
<Link to="/xxxxx">Demo</Link>
- 3.展示区写Route标签进行路径的匹配
<Route path='/xxxx' component={Demo}/>
- 4.
<App>
的最外侧包裹了一个<BrowserRouter>
或<HashRouter>
效果展示:
首先创建两个组件,然后在App.js文件中引用, 接着到index.js文件中注册App组件,最后用index.html文件渲染到页面上
App.js:
import React, { Component } from 'react'
import {Link,Route} from 'react-router-dom'
import Home from './components/Home'
import About from './components/About'
export default class App extends Component {
render() {
return (
<div>
<div className="row">
<div className="col-xs-offset-2 col-xs-8">
<div className="page-header"><h2>React Router Demo</h2></div>
</div>
</div>
<div className="row">
<div className="col-xs-2 col-xs-offset-2">
<div className="list-group">
{/* 原生html中,靠<a>跳转不同的页面 */}
{/* <a className="list-group-item" href="./about.html">About</a>
<a className="list-group-item active" href="./home.html">Home</a> */}
{/* 在React中靠路由链接实现切换组件--编写路由链接 */}
<Link className="list-group-item" to="/about">About</Link>
<Link className="list-group-item" to="/home">Home</Link>
</div>
</div>
<div className="col-xs-6">
<div className="panel">
<div className="panel-body">
{/* 注册路由 */}
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
</div>
</div>
</div>
</div>
</div>
)
}
}
Home组件:
import React, { Component } from 'react'
export default class About extends Component {
render() {
return (
<h3>我是About的内容</h3>
)
}
}
About组件:
import React, { Component } from 'react'
export default class About extends Component {
render() {
return (
<h3>我是About的内容</h3>
)
}
}
index.js文件:
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import {BrowserRouter} from 'react-router-dom'
ReactDOM.render(
<BrowserRouter> // <App>的最外侧包襄了一个<BrowserRouter>或<HashRouter>
<App/>
</BrowserRouter>,
document.getElementById('root')
)
index.html文件:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>react脚手架</title>
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<link rel="stylesheet" href="/css/bootstrap.css">
</head>
<body>
<div id="root"></div>
</body>
</html>
以上是关于React 路由概念详解的主要内容,如果未能解决你的问题,请参考以下文章