一、SPA单页面
1、单页Web应用(单个html)
2、整个应用只有一个完整的页面
3、点击页面中的链接不会刷新页面,只会做页面的局部刷新
4、数据都需要通过ajax请求获取,并在前端异步展现
二、路由的理解
1、什么是路由
一个路由就是一个映射关系(key:value);key为路径,value可能就是function或component
2、路由的分类
1)后端路由:value是fuction,用来处理客户端提交的请求;
注册路由:router.get(path,function(req,res));
工作过程:当node接收到一个请求时,根据请求路径找到匹配的路由,调用路由中的函数来处理请求,返回响应数据
2)前端路由:浏览器端路由,value是component,用于展示页面内容
注册路由:<Route path="test" component={Test}>
工作过程:当浏览器的path变为/test时,当前的路由组件就会变成Test组件
路由HISTORY有两种方式:History.createBrowserHistory(),直接使用H5推出的history身上的API;History.createHashHistory(),hash值(锚点)有历史记录,但是值的改变不会出发页面变化
3、react-router-dom的理解
react的一个插件库;专门用来实现一个SPA应用;基于react的下你项目基本都会用到此库。
1) Link、Route与BrowserRouter
import { Link,BrowserRouter } from 'react-router-dom' //在react中靠路由链接实现切换路由--编写路由链接 <BrowserRouter> <Link to="/about">关于</Link> </BrowserRouter>import { Route,BrowserRouter } import 'react-router-dom' //注册路由 <BrowserRouter> <Route path="/about" component={About}/> </BrowserRouter>浏览器地址栏为 https://xxx.xxx.xxx:xxxx/about
2)HashRouter
import { Link,HashRouter } from 'react-router-dom' <HashRouter> <Link to="/about">关于</Link> </HashRouter>import { Route,HashRouter } import 'react-router-dom' <HashRouter> <Route path="/about" component={About}/> </HashRouter>浏览器地址栏为 https://xxx.xxx.xxx:xxxx/#/about
注:由于Link与Route都需要BrowserRouter包裹,且不能在项目中多次出现<BrowserRouter>或<HashRouter>,我们在项目中的index.js里对<App>进行包裹
import React from 'react' import ReactDOM from 'react-dom' import { BrowserRouter } from 'react-router-dom' import App from './App ReactDOM.render( <BrowserRouter> <App/> </BrowserRouter>, document.getElementById('root') )3)路由组件与一般组件
1.写法不同:
一般组件:<Demo />
路由组件:<Route path="/about" component={About}/>
2.存放的位置不同
一般组件:component
路由组件:pages
3.接收到的props不同
一般组件:写组件标签时传递了什么,就能接收到什么
路由组件:接收到3个固定的属性 history、location、match
4)NavLink
如果实现如图所示的效果:点击About或Home的话,路由会高亮。按照bootstript的写法
<BrowserRouter> <Link to="/about" active>About</Link> <Link to="/home">Home</Link> </BrowserRouter>需要在Link里添加active
import { NavLink,BrowserRouter } from 'react-router-dom' <BrowserRouter> <NavLink to="/about">About</NavLink> <NavLink to="/home">Home</NavLink> </BrowserRouter>使用NavLink的话,react就会默认添加了active,点击路由,被激活的路由自然而然加了背景色,此外如果觉得默认的样式不好看的话,可以在NavLink加"activeClassName"给路由添加激活状态的样式,这里的激活状态样式应该加高权重。
5)封装NavLink
import { React,{Component}} from 'react' import { NavLink,BrowserRouter } from 'react-router-dom' export default MyNavLink extends Component { render(){ coonst { to,title } = this.props return ( <BrowserRouter> <NavLink to={to}>{title}</NavLink> </BrowserRouter> ) } }<MyNavLink to="/ablut" title="关于"></MyNavLink>此外,如果给MyNavLink传递的过多,可以直接用{...this.props}展开
import { React,{Component}} from 'react' import { NavLink,BrowserRouter } from 'react-router-dom' export default MyNavLink extends Component { render(){ coonst { title } = this.props return ( <BrowserRouter> <NavLink {...this.props}>{title}</NavLink> </BrowserRouter> ) } }另外如果我想以"<MyNavLink to="/ablut">关于</MyNavLink>"的形式呢?这也是可以封装的
上个代码示例中,打印this.props的话,会有个children属性
import { React,{Component}} from 'react' import { NavLink,BrowserRouter } from 'react-router-dom' export default MyNavLink extends Component { render(){ console.log(this.props) return ( <BrowserRouter> <NavLink {...this.props} /> </BrowserRouter> ) } }6) Switch的使用
import { Route,BrowserRouter } import 'react-router-dom' <BrowserRouter> <Route path="/about" component={About}/> <Route path="/about" component={Home}/> </BrowserRouter>以上的情况:如果路由是"/about"的话,组件About和Home都会显示出来,也就是说路由在匹配到路由时会继续往下进行匹配,如果路由多的话,不仅会耗性能还会出现意想不到的内容下是出来,所以我们可以使用Switch进行包裹,当匹配到适合的路由就停止往下继续匹配
import { Route,BrowserRouter,Switch } import 'react-router-dom' <BrowserRouter> <Switch> <Route path="/about" component={About}/> <Route path="/about" component={Home}/> </Switch> </BrowserRouter>通常情况下,path与component是一一对应关系,Switch可以提高路由的匹配效率(单一匹配)
7)样式丢失问题
项目启动的本地路径http://XXX.XXX.XXX.XXX:XXXX,这是内置devServe服务器的请求地址,当后面跟的路径是在路由中不存在时(多级路由),react会默认展示为public文件下的index.html页面。
1、public/index.html中引入样式时,不写 ./ 要写 /
2、public/index.html中引入样式的改为"%PUBLIC_URL%/css"
2、在根组件使用HashRouter包裹
8)路由的模糊匹配
import { Route,BrowserRouter,Switch } import 'react-router-dom' <BrowserRouter> <Switch> <Route path="/home" component={Home}/> //home页面 <Route path="/home/a/b" component={Home}/> //没有a文件b页面,依旧显示home <Route path="/a/home/b" component={Home}/> //没有a文件b页面,什么也不显示 //以上就是路由的模糊匹配,从左到右依次匹配,有就显示,如果开头就没有,就不继续往下进行匹 配 //相反 <Route exact={true} path="/home" component={Home}/> //严格匹配 <Route exact path="/home" component={Home}/> //严格匹配 </Switch> </BrowserRouter>1.默认使用的是模糊匹配,输入的路径必须包含要匹配的路径,且顺序要一致
2.开启严格模式<Route exact={true} path="/home" component={Home}/>
3.严格匹配不要随便开启,需要时再开,有些时候开启会导致无法继续匹配二级路由
9)Redirct重定向
import { Route,BrowserRouter,Switch,Redirct } import 'react-router-dom' <BrowserRouter> <Switch> <Route path="/home" component={Home}/> <Route path="/about" component={About}/> <Redirct path="/home" /> //当路由没有/home、没有/about,页面会直接显示home页面。 </Switch> </BrowserRouter>一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由
10)嵌套路由
import { Route,BrowserRouter,Switch } import 'react-router-dom' <BrowserRouter> <Switch> <Route path="/about/a" component={About}/> <Route exact path="/home/about" component={Home}/> // 路由是/home,页面是不会展示的 <Redirct path="/home/b"> </Switch> </BrowserRouter>1.注册子路由时要写上父路由的path值
2.路由的匹配是按照路由的顺序进行的
三、路由传参
1、向路由组件传递params参数
import { BrowserRouter, Link,Route } from 'react-router-dom' <BrowserRouter> //向路由组件传递params参数 <Link to="{`/about/${参数}`}" active>About</Link> //声明接收params参数 <Route path="/about:params" component={About} /> // <Link to="{`/about/${参数1}/{参数二}`}" active>About</Link> //<Route path="/about/:params1/:params2"component={About} /> </BrowserRouter>在About组件中打印 this.props
this.props.match.params就是你传递的路由参数集合。
* 路由链接(携带参数) <Link to="/about/18">About</Link>
* 注册路由(声明接收) <Route path="/about/:params1" component={About} />
* 接收参数 const { params1 } = this.props.match.params
2、向路由组件传递search参数
import { BrowserRouter, Link,Route } from 'react-router-dom' <BrowserRouter> //向路由组件传递search参数 <Link to="{`/about/?params=${this.state.params1}`}">About</Link> //search无需声明,正常注册 <Route path="/about" component={About} /> </BrowserRouter>在About组件中,打印 this.props
开发中,参数最好是对象的形式。
querystring
React内置
import qs from "querystring" let obj = { name:'a',age:18 } qs.stringify(obj) //name=a&age=18 let str = 'name=a&age=18' qs.parse(str) //{ name:'a',age:18 }3、向路由组件传递state参数
import { BrowserRouter, Link,Route } from 'react-router-dom' <BrowserRouter> //向路由组件传递state参数 <Link to="{`/about`,state:{ name:this.state.name,age:this.state.age }}">About</Link> <Route path="/about" component={About} /> </BrowserRouter>在About组件中,打印 this.props
4、push和replace
路由默认是push模式,也就是说路由的变换在浏览器中是有记录的,可以正常执行浏览的回退操作。而replace是替换路由,在浏览器中是没有记录的,
import { BrowserRouter, Link,Route } from 'react-router-dom' <BrowserRouter> <Link replace={true} to="{`/about`,state:{ name:this.state.name,age:this.state.age }}">About</Link> // <Link replace={true} to="{`/about`,state:{ name:this.state.name,age:this.state.age }}">About</Link> <Route path="/about" component={About} /> </BrowserRouter>