Javascript

vue-router和react-router使用的异同点

本文主要是介绍vue-router和react-router使用的异同点,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

前言

对比下vue-router和react-router的使用异同点,以便更好的记忆两者的知识

使用

vue

安装

npm install vue-router
复制代码

man.js中应用他

import Vue from "vue"
import VueRouter from "vue-router"
Vue.use(VueRouter)
//1. 定义路由
let routes = [
  {
    path:'/home',
    name:'home',//给路由命名,
		component:Home,
    meta:{info:'123'}//路由元信息
  },
  {
    path:'/login',
    component:Login
  }
]
//2. 创建路由实例
let router = new VueRouter({
  routes
})
//3. 挂载路由到根实例上
const app = new Vue({
  router
}).$mount('#app')
复制代码

react

安装

npm install react-router-dom
复制代码

使用

import {BrowserRouter,Route} from "react-router-dom"
function App(props){
  return (
    //使用时,一定要在外围包裹一个BrowserRouter或HashRouter
  	<BrowserRouter>
    	<Route path='/home' component={Home}></Route>
      <Route path='/login' component={Login}></Route>
    </BrowserRouter>
  )
}
复制代码

Link标签

vue

<router-link to='/path'>跳转链接</router-link>
<router-link :to="{path:'/path'}">跳转链接</router-link>
//命名路由  等同/user/123
<router-link :to="{name:'user',params:{ userId:123 }}"></router-link>
//带查询参数 等同/user?name=cat
<router-link :to="{name:'user',query:{name:'cat'}}"></router-link>
// replace属性  使用router.replace和不是router.push
<router-link  to="/path" replace></router-link>
复制代码

<router-link>默认是a标签,想替换成span标签,可<router-link tag='span'>

<router-link>点击后,会默认给标签添加.router-link-active类名,可基于这个类名来添加点击态的样式

自定义链接激活时使用的css类名<router-link active-class="激活时的类名">

react

import {Link} from "react-router-dom"
function App(props){
  return (
    <Link to='/path'>跳转链接</Link>
    // 等同 /path?name=cat#the-hash  在组件中可通过this.props.location.state获取Link中的state内容
    <Link to={{pathname:'/path',search:'?name=cat',hash:'#the-hash',state:{info:'123'}}}></Link>
    //func => 返回对象
    <Link to={location=>({...location,pathname:'/path'})}></Link>
    // func => 返回字符串
    <Link to={location=>`${location.pathname}?name=cat`}></Link> 
    // replace
    <Link to='/path' replace>链接</Link>
  )
}
复制代码

Link没有激活属性,需要有激活属性用<NavLink>

import {NavLink} from "react-router-dom"
function App(props){
  return (
    <NavLink to='path' activeClassName='激活态类名'></NavLink>
    <NavLink to='path' activeStyle={{color:'red'}}></NavLink>
  )
}
复制代码

视图组件

视图组件,解决匹配到路由时,组件在哪里渲染的问题

vue

<router-view>会渲染路径匹配到的视图组件

//App.vue
<template>
    <div>
        我是app组件
        <router-view></router-view>
    </div>
</template>
// user.vue
<template>
    <div>
        我是user组件
        <router-view></router-view>
    </div>
</template>
// name.vue
<template>
    <div>
        我是name组件
    </div>
</template>
// routes
<script>
const router = new VueRouter({
    routes:[
      {
        path:'/user',
        component:user,
        children:[
          path:'/user/name',
          component:name
        ]
      }
    ]
})
</script>
复制代码

当路由匹配/user时,会将user组件渲染到App.vue中的router-view的位置

当路经匹配到/user/name时。name组件渲染到user.vue中的router-view的位置,uer组件渲染到App.vuew的router-view的位置

当一个路由要渲染多个组件时,可以使用命名视图

<router-view class='view one'></router-view>
<router-view class='view two' name='a'></router-view>
<router-view class='view three' name='b'></router-view>
<script>
const router = new VueRouter({
    routes:[
      {
        path:'/',
        components:[//记得加s
          default:componentOne,
          a:componentTwo,
          b:componentThree
        ]
      }
    ]
  })
</script>
复制代码

react

<Route> 负责匹配路由负责路视图渲染的位置,<Route>在哪,组件就渲染在哪

<Route>渲染组件的三种方式

<Route component={Home}></Route>//路由匹配到时渲染
<Route children={Home}></Route>// 路由不管有没有匹配上,都会渲染
<Route><Home></Home></Route>// 等同上面,不管有没有匹配上,都会渲染
复制代码
// value 是[history,loacation,match]三个对象
<Route render={value=><Home {...value}></Home>}></Route>
复制代码

children的方式会覆盖component和render

children不管路由匹不匹配都会渲染,render和component只有在路由匹配时渲染

路由对象

vue

在组件中this.$route即可拿到路由对象

  • $route.path当前路由的绝对路径/user/name

  • $route.params获取动态路由的参数

    当路由是这样设计时:path:'/user/:id',浏览器访问'/user/123'时,在user组件中this.$route.params.id即可获取id值123

  • $route.query获取查询参数

    访问/user?name=123,在user组件this.$route.query.name即可获取查询参数

react

在react中,要获取路由对象,必须在组件外层包裹上withRouter

function App(props){
  return (
  	<Route path='/home' component={Home}></Route>
  )
}
// Home.jsx
import {withRouter} from "react-router-dom"
class Home extends Component{
  render(){
    return <div>home</div>
  }
}
export default withRouter(Home)
复制代码

只有包裹上withRouter ,Home组件的props中才有history,location,match三个对象

  • history
    • action,可得知路由栈的操作是POP,PUSH,REPLACE
  • location
    • pathname当前路由的绝对路径
    • search查询参数,访问/user?userId=123=>可拿到?userId=123
    • hash:#the-hash
    • state:类似vue的路由元信息meta ,在这里的存储的信息不会明文显示在浏览器上
  • match
    • params<Route to='/user/:id'/ component={user}>,访问/user/123user组件中。this.props.match.params.id可以获取id
    • isExact,当前路由是不是完全匹配

编程式导航

vue

$route是路由对象,而$router上挂载方法

  • this.$router.push('/path')
  • this.$router.push({path:'/path'})
  • this.$router.push({name:'user',params:{id:123}})等同/user/123
  • this.$router.push({name:'user,query:{name:'123'}'})等同/user?name=123
  • this.$router.replace()同上,不会向路由栈中添加新路由,只会替换当前路由
  • this.$router.go(1)向前进一步,等同history.forward()
  • this.$router.go(-1)后退一步

react

  • this.props.history.push('/user',{info:123}),第一个参数path,第二个是state(类似vue路由的元信息)
  • this.props.history.replace(path,state)
  • this.props.history.go(n)等同vuerouter
  • this.props.history.goBack()浏览器回退一步
  • this.props.history.forForward()浏览器前进一步

全局导航守卫

用于保护那些需要权限才能访问的页面

vue

import Vue from "vue"
import VueRouter from "vue-router"
Vue.use(VueRouter)
let router=new VueRouter({
  routes:[
    {
      path:'/login',
      component:Login
      name:'login'
    },
    {
      path:'/home',
      component:home,
      name:'home'
    },
    {
      path:'/user',
      name:'user'
      component:User
    }
  ]
})
//路由白名单,没有权限也能访问的页面
let whiteList = ['/login','/home']
//全局前置导航守卫,每次跳转前都会调用该
router.beforeEach((to,from,next)=>{
  //to是将要访问的路由对象
  //from是将要离开的路由对象
  //访问路径在白名单内,任其跳转
  if(whitelist.includes(to.path){
     next()//记住一定要next()
  }else{
    if(isLogin)//已经登录的,任其跳转
      next()
    }else{
      next('/login')//没有登录的跳转到登录页面
    }
  }
})
复制代码

react

在路由组件中,this.props.history.listen(fn)可以监听路由的变化,我们可以在路由跟组件,监听路由变化,做出相应的跳转

// App.jsx
function App(){
  <BrowserRouter>
  	<RouterGuard></RouterGuard>
  </BrowserRouter>
}
// RouterGuard.jsx
import {withRouter,Route} from "react-router"
class RouterGuard extends Component{
  whilteList=['/login','/home']
  componentDidMount() {
		this.unlisten = this.props.histroy.listen((location, action) => {
      //location是路由对象,action是操作路由栈的方式
			let { pathname } = location;
      //访问路径不在白名单内并且没有登录
			if(!this.whiteList.includes(pathname)&&!isLogin){
        this.props.history.replace('/login')
      }
		});
	}
  // 组件卸载时,解除监听
  componentWillUnmount() {
		this.unlisten();
	}
  render(){
    return (
      <>
      // 在这里写路由
    		<Route path='/home' component={home}></Route>
      ...
      // 也可使用下面将使用的方法getRoue()
      </>
    )
  }
}
export default withRouter(RouterGuard)
复制代码

##react模拟vue配置路由的方式

// routerConfig.js
import Login from './view/Login';
import Home from './view/Home';
import Root from './view/Root';
let routes = [
	{
		path: '/',
		component: Root,
		children: [
			{
				path: '/login',
				component: Login,
			},
			{
				path: '/home',
				component: Home,
			},
		],
	},
];
// 将路由path转化成绝对路径
routes.forEach(item => {
	if (item.children) {
		item.children.map(child => {
			if (!child.path.startsWith('/')) {
				child.path = item.path + child.path;
			}
		});
	}
});
export default routes
复制代码

在写个组件遍历routes,返回<Route>组件

function getRoute(routes){
  //1. 判断routes是不是array
  if(!Array.isArray(routes)){
    return null;
  }
  // 遍历routes
  let routesDom = routes.map((item,index)=>{
    // 解构出item中的children,递归处理children
    let {children,component:Component,render,..rest} = item;
    return <Route
            key={index}
            {...rest}
            render={value=>{
            // value是[history,location,match]等信息
                <Component {...value}>
                //递归处理children
        	    {getRoute(children)}
                </Component>
            }}/>
  })
  return <Switch>//switch组件保证只匹配一个路由(从上到下)
  	 {routesDom}
        </Switch>
}
export default withRouter(getRoute)
复制代码

使用

function App(){
  return (
    <BrowserRouter>
    	<getRoute></getRoute>
    </BrowserRouter>
  )
}
复制代码

路由元信息

使用路由元信息来设置页面的title

vue

import Vue from 'vue'
import VueRouter from "vue-router"
Vue.use(VueRouter)
let router = new VueRouter({
  routes:[
    {
      path:'/home',
      component:Home,
      meta:{title:'首页'}//路由元信息,不会明文显示在浏览器上
    }
  ]
})
router.beforeEach((to,from,next)=>{
  let title = to.meta.title
  document.title=title
})
复制代码

react

在组件中设置location.state

this.props.location.state={title:'首页'}

//在根组件中监听路由变化
componentDidMount(){
  this.unlisten = this.props.history.listen((location,action)=>{
    const {title}=location.state
    document.title=title
  })
}
componentWillUnmount(){
  this.unlisten()
}
复制代码

路由跳转阻塞

当用户在一个页面中的input中输入了内容,还没保存就要跳转页面时,应该给予提示,此时阻塞路由

vue

导航守卫,组件独享的拦截器

beforeRouteLeave(to, from, nexxt) {
  const allowTransition = window.confirm('确定跳转?')
  if (allowTransition) {
    next()//继续跳转
  } else {
    next(false)//取消跳转
  }
},
复制代码

react

componentDidMount(){
  this.unblock = this.props.history.block((localtion,action)=>{
  	// location是将要跳转的路由对象
  	return '离开?'
	})
}
//组件销毁时解除监听
componentWillUnmount() {
	this.unblock();
}
复制代码

image-20200519100351736

如果想要自定义提示,

<BrowserRouter
  getUserConfirmation={(message, callback) => {
    // this is the default behavior
    //const allowTransition = window.confirm(message);
    //callback(allowTransition);
    message就是history.block传递过来的信息‘离开’
    接收message后,你可以自定义弹出一个modal来获取用户的操作
    callback(boolean)//true则跳转,false则不跳转
  }}
/>
复制代码

结语

作者:胡志武

时间:2020/05/21

如果文中有错漏处,请看官们指正,如果觉得写得不错,请点个赞吧!

这篇关于vue-router和react-router使用的异同点的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!