路由
后端路由
path(路由分发)
针对不同的路由对应不同的回调函数处理(req, res, next)
req;获取请求参数
res:返回请求数据
next: 调用后续的回调函数
前端路由
* 路由是根据不同的url去请求不同的页面内容
* 前端路由就是把不同路由对应不同的内容或页面的任务交给前端来做,之前是通过服务端根据url不同返回不同的页面来实现。
* 利用H5的history.pushState 和 history.replaceState ,这两个history新增的api,为前端操控浏览器历史栈提供了可能性
* 这两个Api都会操作浏览器的历史栈,而不会引起页面的刷新。
* 不同的是,pushState会增加一条新的历史记录,而replaceState则会替换当前的历史记录。
应用:单页面应用(所有的活动局限于一个页面,页面有数据变化的时候不会刷新整个页面,局部刷新---ajax来进行数据的收发)
优点和缺点:
* 优点: 用户体验好,不需要每次向服务器发送请求请求页面数据,响应快
* 缺点:使用浏览器的前进,后退键的时候会重新发送请求,没有合理地利用缓存,
问题:
1、基于Ajax 的 Web 应用最为明显的特征在于使用了浏览器内部原生支持的 XMLHttpRequest对象与后台服务器进行数据通。
2、由于这种通信方式不需要页面的刷新动作,因而无论与后台发生了多少次通信,浏览器的 URL 会一直保持在初始地址不变。
3、这随之而来的一个问题便是不断变化的页面状态信息无法记录到浏览器的历史记录堆栈中,从而使得用户无法通过浏览器的前进 / 后退按钮在不同状态页面间进行切换。
解决思路:
浏览器能够支持在用户访问过的页面间进行前进 / 后退的操作,依赖于内部维持的 history 对象。出于安全性的考虑,
浏览器并不允许 JavaScript 脚本对该对象进行增删改之类写操作,而只是可以通过 history. back/forward() 等方法进行访问。
既然在页面状态发生变化时,无法通过脚本直接去影响浏览器的历史信息,那么只有通过 URL 的变化来触发浏览器增加一条新的历史记录。 这也就是说需要将 Ajax 应用的不同页面状态与 URL 进行一种一对一的映射,并且能够在回退或前进到某一 URL 之时,应用本身能够在页面无刷新的情况下跳转到正确的页面状态。
如何对 Ajax 应用的初始 URL 进行改变,而同时这种变化的切换又不会引起页面的重新加载呢?
答案只有一个,那就是借助用于页面内资源片段定位目的的“片段标识符”(fragment identifier),即 URL 中“#”符号后的字符串(hash string)。当浏览器向服务器端请求资源时,片段标识符并不会连同 base URL 一同发往服务器端,而只是在得到服务器返回的结果之后帮助浏览器快速定位到被相应的锚点(anchor)所标识的资源片段,即使无法找个对应的锚点,浏览器也并不会报错。正是基于浏览器的这一特性,构建片段标识符与页面状态之间的映射关系成为了解决此类问题的基础。
关于url中#的作用:
- 学习: http://www.ruanyifeng.com/blog/2011/03/url_hash.html
- '#'代表网页中的一个位置。其右面的字符,就是该位置的标识符即hash string
- 改变#不触发网页重载
- 改变#会改变浏览器的访问历史
- window.location.hash读取#值
- window.onhashchange = func 监听hash改变
React中的路由库:react-router
- github主页: https://github.com/ReactTraining/react-router
- 官网教程: https://github.com/reactjs/react-router-tutorial/(官方教程)
- 一峰教程: http://www.ruanyifeng.com/blog/2016/05/react_router.html?utm_source=tool.lu
react-router库中的相关组件
包含的相关组件:
- Router: 路由器组件, 用来包含各个路由组件,用来管理路由
- Route: 路由组件, 注册路由
- IndexRoute: 默认路由组件
- hashHistory: 路由的切换由URL的hash变化决定,即URL的#部分发生变化
- Link: 路由链接组件,生成a标签的
Router: 路由器组件
* 属性: history={hashHistory} 用来监听浏览器地址栏的变化, 并将URL解析成一个地址对象,供React Router匹配
* 子组件: Route
Route: 路由组件
* 属性1: path="/xxx"
* 属性2: component={Xxx}
* 根路由组件: path="/"的组件, 一般为App
* 子路由组件: 子<Route>配置的组件
IndexRoute: 默认路由
* 当父路由被请求时, 默认就会请求此路由组件
hashHistory
* 用于Router组件的history属性
* 作用: 为地址url生成?_k=hash, 用于内部保存对应的state
Link: 路由链接
* 属性1: to="/xxx" ;值是路由地址
* 属性2: activeClassName="active"
使用步骤:
1.创建应用
create-react-app hello-router
2、下载相关插件:
npm install react-router@3 --save
3、编码
About.js
import React from 'react'
class About extends React.Component{
render() {
return(
<div>
<p>about组件内容</p>
</div>
);
}
}
export default About;
Repos.js
import React from 'react'
class App extends React.Component{
render() {
return(
<div>
<p>repos组件内容</p>
</div>
);
}
}
export default App;
Home.js
import React from 'react'
class Home extends React.Component{
render() {
return(
<div>
<p>home组件内容</p>
</div>
);
}
}
export default Home;
App.js
import React from 'react'
import {Link} from 'react-router';
/**
点击<Link to='/about'>about</Link>时,不跳转,而是改变url中的地址,改变片段标识符即#号后面的值
* {this.props.children} 表示当前组件的子组件,同时表示当前请求的是哪个子组件
*/
class App extends React.Component{
render() {
return(
<div>
<ul>
<li><Link to='/about'>about</Link></li>
<li><Link to='/repos'>repos</Link></li>
</ul>
<div>
{this.props.children}
</div>
</div>
);
}
}
export default App;
index.js
import React from 'react'
import ReactDom from 'react-dom';
import App from '../src/components/App'
import About from '../src/components/About'
import Home from '../src/components/Home'
import Repos from '../src/components/Repos'
import {Router,Route,hashHistory,IndexRoute} from 'react-router'
/*
* 用路由的时候不是直接渲染组件,而是注册路由
* 1、引入路由器
* 2、注册路由 path='/' ;path='/about'
* Route,所有的路由都在路由器中
* 3、组件有嵌套,路由也有嵌套,
* 4、所有的组件不用在根组件App中引入,而是在index.js中直接引入注册
* */
ReactDom.render(
(
<Router history={hashHistory}>
<Route path='/' component={App}>
<IndexRoute component={Home}></IndexRoute>
<Route path='/about' component={About}></Route>
<Route path='/repos' component={Repos}></Route>
</Route>
</Router>
),
document.getElementById('root')
);
目录如下:
npm start
启动后页面如下:
路由的嵌套:Repos里在嵌套一个路由Rep
Rep.js
import React from 'react'
class Rep extends React.Component{
render() {
return(
<div>
<p>公司:{this.props.params.name}, 产品:{this.props.params.pro}</p>
</div>
);
}
}
export default Rep;
当用占位符请求路由时,该路由props对象中有params属性,该属性中以占位符变量为key,请求路径中的值为value ,如下图:
index.js注册路由
<Route path='/repos' component={Repos}>
<Route path='/repos/:name/:pro' component={Rep}></Route>
</Route>
占位符 /:xxx 当请求的路由路径不确定的时候可以用占位符表示,xxx表示变量,随意起名,等待请求路径填充
Repos.js
import React from 'react'
import {Link} from "react-router";
class Repos extends React.Component{
constructor(props){
super(props);
this.state={
repos:[
{name:'ali',pro:'支付宝'},
{name:'ten',pro:'王者荣耀'}
]
}
}
render() {
return(
<div>
<ul>
{
this.state.repos.map((item,index)=>{
return (<li key={index} ><Link to={`/repos/${item.name}/${item.pro}`}>{item.pro}</Link></li>)
})
}
</ul>
{this.props.children}
</div>
);
}
}
export default Repos;