Vue路由

注意:随着版本更新,vue版本需要对应合适的vue-router版本才能正常工作,比如这里当我安装vue-router时,

npm install vue-router

它默认安装的版本是4.0以上的,在我这个vue2.0版本会各种报错,跟vuex也要对应合适的版本一样,否则会报错,所以安装的时候需要指定版本

npm install vue-router@3.4.9

同vuex一样,在安装好后需要一个router文件夹管理路由,里面的index.js文件由于创建路由,通过VueRouter创建一个路由器。routes是定义的路由匹配规则,需要交给router管理。

import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
export default new VueRouter({routes : [{path:"/about",component:AboutCom},{path:"/home",component:HomeCom,children:[{//  path:'/news',这里的/一定要删除是个坑,不然子路由组件渲染不出来path:'news',component:NewCom},{// path:'/message',这里的/一定要删除是个坑,不然子路由组件渲染不出来path:'message',component:MessageCom,children:[{//传递params参数 需要路由定义时声明// path:"detail/:id/:title/:content",//传递query参数不需要声明path:"detail",component:DetailCom,name:'xiangqing' ,  props(route){console.log(route)const {id,title,content} = route.queryreturn {id,title,content}}        }]},]},]
})

main.js里需要引入这个路由器并挂载到vue实例vc

import router from './router'new Vue({el:"#app",router,render: h => h(App),
})

上面代码是整体代码,一步一步来,
Vue路由和React路由-编程知识网
Vue路由和React路由-编程知识网

在APP组件里 有两个链接,about和home,这解析出来其实就是a标签 About组件和Home组件由路由控制显示,所以这两个组件是路由组件,就需要在router里定义这两个组件,现在pages文件夹里定义好这两个组件 pages/Home和pages/About,然后在路由器里引入组件开始定义匹配规则

import AboutCom from '../pages/AboutCom'
import HomeCom from '../pages/HomeCom'routes : [{path:"/about",component:AboutCom},{path:"/home",component:HomeCom,

这样在页面里,通过router-link作为a标签,同时router-view作为占位,到时候路由匹配到哪个组件就展示哪个组件

<router-link to="/about">about</router-link>&nbsp;&nbsp;&nbsp;<!-- <a href="">home</a> --><router-link to="/home">home</router-link>&nbsp;&nbsp;&nbsp;<router-view></router-view>

这样一级路由就完成了。
接下来是二级路由Home组件里 ,又有导航区 和展示区
Vue路由和React路由-编程知识网
在home的路由里通过children定义子路由

 {path:"/home",component:HomeCom,children:[{//  path:'/news',这里的/一定要删除是个坑,不然子路由组件渲染不出来path:'news',component:NewCom},{// path:'/message',这里的/一定要删除是个坑,不然子路由组件渲染不出来path:'message',component:MessageCom,

注意

   path:'news',

没有/,这是坑,加了的话组件等会儿就展示不出来,其余跟一级组件同理,接着是三级路由,
Vue路由和React路由-编程知识网

接着在message里通过children定义子路由

 path:'message',component:MessageCom,children:[{//传递params参数 需要路由定义时声明// path:"detail/:id/:title/:content",//传递query参数不需要声明path:"detail",component:DetailCom,

其余地方跟一级路由同理,这样一个嵌套路由就完成了。

vue路由传参

1.传递params参数

params参数在地址栏表现为
Vue路由和React路由-编程知识网
传递params参数需要在路由定义时声明接收params参数

 //传递params参数 需要路由定义时声明path:"detail/:id/:title/:content",

在页面的router-link里是使用模板字符串传递的

<router-link :to="`/home/message/detail/${msg.id}/${msg.title}/${msg.content}`">{{msg.title}}</router-link>

params参数藏在$sroute.params里,所以页面要获取这些params可以

<li>id:{{$route.params.id}}</li>

2.传递query参数

传递query参数在路由定义时不用声明,在浏览器地址栏表现为
Vue路由和React路由-编程知识网
在路由定义时

 //传递query参数不需要声明path:"detail",

在页面的router-link也是模板字符串

<router-link :to="`/home/message/detail/?id={msg.id}&title=${msg.title}&content={msg.content}`">{{msg.title}}</router-link>

query参数藏在$sroute.query里,所以页面要获取这些params可以

<li>id:{{$route.query.id}}</li>

命名路由简化跳转方式

可以在路由定义时给路由命名,方式时name:"名字“

            path:"detail",component:DetailCom,name:'xiangqing' ,  

在页面的router-link进行跳转时就可以这样写

 <!-- 通过命名路由的方式传参 --><router-link :to="{name:'xiangqing',query:{id:msg.id,title:msg.title,content:msg.content}}">{{msg.title}}</router-link>

当然这里也可以由params加入,具体是看路由定义时规定的时哪些值由params传递,哪些由query传递,这样就省略了path一长串。

路由的props配置

想象这样一个场景,点击一条消息进入消息的详情页,需要展示消息的id,title,content等,由于这些信息全保存在$route里所以可以在页面通过params或者query取出
params:

  <li>id:{{$route.params.id}}</li><li>消息:{{$route.params.title}}</li><li>内容:{{$route.params.content}}</li> 

query:

   <li>id:{{$route.query.id}}</li><li>消息:{{$route.query.title}}</li><li>内容:{{$route.query.content}}</li> 

这样代码过于冗余,可以在computed里进行处理再显示,不再赘述,另一种方法是在路由定义时通过props的方式传递,同时在组件里通过props[‘id’,‘title’,‘content’]接收,一般父组件给子组件传值就是这种方式,具体做法是在路由定义时

props:{carName:"奔驰"}这是通过props映射自定义的静态数据
props:true表示映射params参数为props传给路由组件
如果还想映射query参数为props传给路由组件,则必须把props写成props(route){const {id,title,content} = route.queryreturn {id,title,content}}        

这里的route是直接放在router管理的,才能取到这个route,放在外面定义好交给router管理的取不到。在页面组件需要定义props接收参数

<script>export default {props:['id','title','content']}
</script>

在页面就可以直接用数据了

    <li>id:{{id}}</li><li>消息:{{title}}</li><li>内容:{{content}}</li>

编程式路由导航

replace – 替换当前记录 不能返回 通过点击事件跳转

this.$router.push(path)this.$router.replace(path)this.$router.back()this.$router.go(-1)this.$router.go(1)
  pushShow(msg){this.$router.push({   name:'xiangqing',query:{id:msg.id,title:msg.title,content:msg.content}})}

缓存路由组件

Vue路由和React路由-编程知识网
有这样一个需求,点击News 显示NewCom组件,点击Message显示MessageCom组件,在NewCom组件里输入东西后,点击Message后,再点击News会导致NewCom组件输入内容清空,这是因为在路由的切换过程中,伴随着组件的挂载和卸载,为了使NewCom组件输入框里的内容保持不变,就许哟啊一个keep-alive包裹这个组件的router-view,这样就行了

          <keep-alive><router-view></router-view></keep-alive>

但是,这样做会使得MessageCom的组件也在切换过程中不销毁,为了解决这个问题 只保证NewComers组件不销毁,可以这样添加一个include

   <keep-alive include="NewCom"><router-view></router-view></keep-alive>

这个NewCom对应的是这个组件的名字NewCom,NewCom.vue

export default({name:"NewCom",
})

React路由

说明:react的路由是安装react-router-dom包,现在已经更新到react-router-dom 6版本 因为本例中说明的是5版本的react-router-dom,所以必须安装对应的版本才能正确运行。
步骤:
第一步就是安装路由

npm install react-router-dom@5

拿到静态页面,观察到哪些是一般组件 ,哪些是路由组件,哪些是导航区,哪些是路由展示区
在App页引入页面,分离出导航区和组件展示区。原来的a标签在react里是LInk标签所以需要

import {Link} from 'react-router-dom'

然后把a标签改写成Link

<a className="list-group-item" href="./about.html">About</a>改写成
<Link className="list-group-item" to="/about">About</Link>

由to定义路由的路径,接着在路由展示区的地方注册路由,需要先引入Route

import {Link,Route} from 'react-router-dom'
 <Route path='/about' component={About}></Route>

备注:需要把整个App组件包裹在BrowserRouter组件里,这样才不会错

import {BrowserRouter} from 'react-router-dom'ReactDOM.render( <BrowserRouter><App /></BrowserRouter>,document.getElementById('root'))

本例中使用到bootstrap 需要在index.html里引入

<link rel="stylesheet" href="%PUBLIC_URL%/css/bootstrap.css">

表示从本地路径下的css找到bootstrap.css
效果图:
Vue路由和React路由-编程知识网

NavLink的使用

一般导航区的导航点击了都会高亮显示,如果有这样的需求,那就需要把Link换为NavLink。它的原理是谁被点击了 就给当前这个导航链接加上active这个class

<NavLink className="list-group-item" to="/about">About</NavLink>

Vue路由和React路由-编程知识网
修改样式:如果需要自己定义active的样式。NavLink接受一个activeClassName=“myActive”,myActive是我自己定义的名字,随意。然后在index.html里定义自己的myActive

 <style>.myActive{background-color: red !important;color: white !important;}</style>
      <NavLink activeClassName="myActive" className="list-group-item" to="/about">About</NavLink><NavLink activeClassName="myActive" className="list-group-item" to="/home">Home</NavLink>

Vue路由和React路由-编程知识网

封装NavLink组件

应用场景:如果上面的NavLink有很多很多个

<NavLink className="list-group-item" to="/about">About</NavLink>
<NavLink className="list-group-item" to="/abou">abou</NavLink>
<NavLink className="list-group-item" to="/abo">abo</NavLink>
<NavLink className="list-group-item" to="/ab">ab</NavLink>
<NavLink className="list-group-item" to="/a">a</NavLink>
<NavLink className="list-group-item" to="/abouty">abouty</NavLink>
<NavLink className="list-group-item" to="/aboueet">aboueet</NavLink>

上面的NavLink除了to的值不一样其他都一样,这样写显得过于冗余,所以对NavLink进行二次封装
创建MyNavLink组件

import {NavLink} from 'react-router-dom'//使用原始的NavLink做改装
import React, { Component } from 'react'export default class MyNavLink extends Component {render() {console.log(this.props)return (<NavLink activeClassName="myActive" className="list-group-item" {...this.props}>{this.props.children}</NavLink>)}
}
<MyNavLink activeClassName="myActive" className="list-group-item" to="/about">About</MyNavLink>

中的activeClassName=“myActive” className=“list-group-item” to="/about"这些都是作为props传递给了NavLink,由于只有to的值不一样,所以在新的MyNavLink里只需要手动传入to的值。值得一提的是

  <MyNavLink to="/about">about</MyNavLink>

中的about称为元素内容,它也是保存在props里的,为children属性,所以

 <NavLink activeClassName="myActive" className="list-group-item" {...this.props}>{this.props.children}</NavLink>

可以写为自闭合

 <NavLink activeClassName="myActive" className="list-group-item" {...this.props}/>

Switch的使用

Switch用于匹配路由,如果一个路径匹配到两个路由,那么会把两个组件都显示出来,如果这样

   <MyNavLink to="/about">about</MyNavLink>注册路由<Route path='/about' component={About}></Route><Route path='/about' component={Test}></Route>

一个about匹配到两个路由会显示两个组件
Vue路由和React路由-编程知识网
这明显是不对的,这说明路由在匹配成功后还会向后继续匹配,这是损耗性能的,解决办法就是Switch

 <Switch><Route path='/about' component={About}></Route><Route path='/about' component={Test}></Route>//这条不再匹配<Route path='/home' component={Home}></Route></Switch>

Vue路由和React路由-编程知识网

解决样式丢失问题

在路由里随便增加路径会导致bootstrap样式丢失,解决办法是在引入bootstrap的时候

   <link rel="stylesheet" href="%PUBLIC_URL%/css/bootstrap.css">

或者

   <link rel="stylesheet" href="/css/bootstrap.css">

或者使用HashRouter。第一种常用

  <link rel="stylesheet" href="%PUBLIC_URL%/css/bootstrap.css">

路由的模糊匹配和严格匹配

假设有这样一个链接

 <MyNavLink to="/about/a/b">about</MyNavLink>

然后有一些注册的路由

            <Route path='/about' component={About}></Route>

这样也能匹配成功,成功显示About组件,这就是模糊匹配。为了解决这个问题就出现了严格匹配exact

 <MyNavLink to="/about/a/b">about</MyNavLink><Route exact={true} path='/about' component={About}></Route>

这样就开启了严格匹配,但是这个exact对子路由的匹配有影响,导致无法继续匹配二级路由。需要谨慎使用。

Redirect的使用

Redirect是重定向,当前路由没有路由组件与其匹配时,去Redirect重定向的路由,一般写在路由注册的最后面
Vue路由和React路由-编程知识网
没有匹配的 则不显示组件,当Redirect重定向后

import {Route,Switch,Redirect} from 'react-router-dom'<Switch><Route path='/about' component={About}></Route><Route path='/home' component={Home}></Route><Redirect to="/about"></Redirect>
</Switch>

那么当
Vue路由和React路由-编程知识网
也会自动跳转到About组件
Vue路由和React路由-编程知识网

嵌套路由

嵌套路由的关键是分清哪个是导航区,哪个是路由组件展示区,导航区自然把a写成Link、NavLink等,那么自然需要从react-router-dom引入这些东西,路由组件展示区就是注册路由的地方,匹配到路由就展示相应的组件

 <NavLink className="list-group-item " to="/home/news">News</NavLink><NavLink  className="list-group-item " to="/home/message">Message</NavLink>

主要是to的嵌套,注册路由时也得对应

  <Switch><Route path="/home/news" component={News}></Route><Route path="/home/message" component={Messages}></Route></Switch>

该引入的东西组件等引入不再赘述。
Vue路由和React路由-编程知识网

 <Switch><Route path="/home/news" component={News}></Route><Route path="/home/message" component={Messages}></Route><Redirect to="/home/news"></Redirect></Switch>

Redirect是 to

react路由传参

react路由有三种传参方式,params、search、state,三种参数都保存在props属性里。

1.params参数

params参数在路由链接的形式是,vue一样

<li key={msgObj.id}><Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link></li>

params参数需要在注册路由时声明接收params参数,跟vue一样

<Route path="/home/message/detail/:id/:title" component={Detail}></Route>

params保存在props.match.params里

2.search参数

search参数可以对标vue里的query参数,跟vue规则一样

<li key={msgObj.id}><Link to={`/home/message/detail/?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link></li>

search参数不需要声明接收,跟vue一样。

<Route path="/home/message/detail" component={Detail}></Route> 

search参数保存在props.location.search中。

?id=1&title="消息1"

但是这个结果是这种形式,用的时候需要自己使用方法切割,queryString是不错的选择

import qs from 'querystring'
const result = qs.parse(this.props.location.search)

3.state参数

state参数不会在浏览器地址栏显示参数信息,,传递的时候以对象形式。

 <li key={msgObj.id}><Link to={{pathname:'/home/message/detail',state:{id:msgObj.id,title:msgObj.title}}}>{msgObj.title}</Link></li>

state参数不用声明接收

   <Route path="/home/message/detail" component={Detail}></Route> 

state保存在props.location.state里。

总结

向路由组件传递参数

			1.params参数路由链接(携带参数):<Link to='/demo/test/tom/18'}>详情</Link>注册路由(声明接收):<Route path="/demo/test/:name/:age" component={Test}/>接收参数:this.props.match.params2.search参数路由链接(携带参数):<Link to='/demo/test?name=tom&age=18'}>详情</Link>注册路由(无需声明,正常注册即可):<Route path="/demo/test" component={Test}/>接收参数:this.props.location.search备注:获取到的search是urlencoded编码字符串,需要借助querystring解析3.state参数路由链接(携带参数):<Link to={{pathname:'/demo/test',state:{name:'tom',age:18}}}>详情</Link>注册路由(无需声明,正常注册即可):<Route path="/demo/test" component={Test}/>接收参数:this.props.location.state备注:刷新也可以保留住参数

编程式路由导航

主要是利用history的API,有以下几个方法
-this.prosp.history.push()
-this.prosp.history.replace()
-this.prosp.history.goBack()
-this.prosp.history.goForward()
-this.prosp.history.go()
这些历史记录以栈的形式保存,push可以前进后退,replace则不能。

this.props.history.push是默认的跳转方式
1.传递params参数:

  <button onClick={()=>{this.pushShow(msgObj.id,msgObj.title)}}>push查看</button>pushShow=(id,title)=>{console.log(this.props)this.props.history.push(`/home/message/detail/${id}/${title}`)}params参数需要声明接收<Route path="/home/message/detail/:id/:title" component={Detail}></Route>

注意:这里pushShow要传参,所以写成一个函数的形式,onClick后面需要的是一个函数而不是一个函数值,所以用了()=>{}包裹。如果不这样this.pushShow()会直接调用(没有点击事件之前就调用)
this.props.history.repplace使用方法一样。
2.传递search参数

<button onClick={()=>{this.pushShow(msgObj.id,msgObj.title)}}>push查看</button>pushShow=(id,title)=>{this.props.history.push(`/home/message/detail/?id=${id}&title=${title}`){/* 接收search参数 */}}<Route path="/home/message/detail" component={Detail}></Route> 

3.传递state参数

 <button onClick={()=>{this.pushShow(msgObj.id,msgObj.title)}}>push查看</button>pushShow=(id,title)=>{对象形式传递statethis.props.history.push('/home/message/detail',{id,title})}{/* 接收state参数也不用声明 */}<Route path="/home/message/detail" component={Detail}></Route> 

Vue路由和React路由-编程知识网
-this.prosp.history.goBack()—回退一步
-this.prosp.history.goForward()前进一步
-this.prosp.history.go() 传入数字 指定前进或后退步数

withRouter的使用

路由能够跳转全靠路由组件的history实现,那么一般组件里想要实现路由跳转怎么办呢?可以通过withRouter把这个一般组件转为一般组件,那么它就能使用history的API跳转链接了
Vue路由和React路由-编程知识网
在一般组件里

import { withRouter } from 'react-router-dom'
 class Header extends Component {render() {return (<div><button onClick={this.back}>后退</button><div className="page-header"><h2>React Router Demo</h2></div></div>)}back=()=>{// console.log(99)this.props.history.goBack()}
}
export default withRouter(Header)

暴露这样一个新的组件就可以了

export default withRouter(Header)

BrowserRouter与HashRouter的区别

		1.底层原理不一样:BrowserRouter使用的是H5的history API,不兼容IE9及以下版本。HashRouter使用的是URL的哈希值。2.path表现形式不一样BrowserRouter的路径中没有#,例如:localhost:3000/demo/testHashRouter的路径包含#,例如:localhost:3000/#/demo/test3.刷新后对路由state参数的影响(1).BrowserRouter没有任何影响,因为state保存在history对象中。(2).HashRouter刷新后会导致路由state参数的丢失!!!4.备注:HashRouter可以用于解决一些路径错误相关的问题。