react router @4 和 vue路由 详解
react router @4 和 vue路由本文大纲: 1、vue路由基础和使用 2、react-router @4用法 3、什么是包容性路由?什么是排他性路由? 4、react路由有两个重要的属性:children和render的区别? 5、react如何在路由里面定义一个子路由? 6、vue如何在路由里面定义一个子路由? 7、react怎么通过路由传参? 8、vue怎么通过路由传参? 9、怎么在react里拿到router对象? 10、怎么在vue里拿到router对象? 11、路由怎么回退? 12、react路由守卫? 13、vue路由守卫? ? ? 1、vue路由基础和使用 a、大概目录 ? ? ? ? ? ? 我这里建了一个router文件夹,文件夹下有index.html? ?
b、准备工作: npm install vue-router 或者 yarn add vue-router
? ? c、配置 必须要通过 Vue.use() 明确地安装路由功能: import Vue from ‘vue‘ import VueRouter from ‘vue-router‘ Vue.use(VueRouter) 附上我的代码:我是将router的内容写在了我的router文件夹下的index.html中,然后暴露出去,在main.js中引入 router文件夹下的index.html import Vue from ‘vue‘ import VueRouter from ‘vue-router‘ Vue.use(VueRouter) import Home from ‘pages/Home‘ import Map from ‘components/Map‘ import Home1 from ‘components/Home1‘ import Find from ‘components/Find‘ import Mine from ‘components/Mine‘ import Type from ‘components/Type‘ import Publish from ‘components/Publish‘ import Search from ‘components/Search‘ import Success from ‘components/Success‘ import Need from ‘components/Need‘ import Position0 from ‘components/Position‘ import Like from ‘components/scrollX/Like‘ import S1 from ‘components/scrollX/1‘ import S2 from ‘components/scrollX/2‘ import Listall from ‘components/mine/Listall‘ import Listone from ‘components/mine/Listone‘ import Listchange from ‘components/mine/Listchange‘ const routes = [ { path:‘/‘,redirect:‘/ho‘ },{ path: ‘/ho‘,redirect:‘/ho/home‘,component: Home,children: [ { name: ‘home‘,path: ‘home‘,component: Home1,redirect:‘/ho/home/like‘,children :[ { name: ‘like‘,path: ‘like‘,component: Like },{ name: ‘2000001‘,path: ‘2000001‘,component: S1 },{ name: ‘2000022‘,path: ‘2000022‘,component: S2 } ] },{ name: ‘type‘,path: ‘type‘,component: Type },{ name: ‘need‘,path: ‘need‘,component: Need },{ name: ‘find‘,path: ‘find‘,component: Find },{ name: ‘mine‘,path: ‘mine‘,component: Mine } ] },{ name: ‘search‘,path: ‘/search‘,component: Search },{ name: ‘position‘,path: ‘/position‘,component: Position0 },{ name: ‘publish‘,path: ‘/publish‘,component: Publish },{ name: ‘success‘,path: ‘/success‘,component: Success },{ name: ‘listall‘,path: ‘/listall‘,component: Listall },{ name: ‘listone‘,path: ‘/listone‘,component: Listone },{ name: ‘listchange‘,path: ‘/listchange‘,component: Listchange },{ name: ‘map‘,path: ‘/map‘,component: Map } ] const router = new VueRouter({ mode: ‘history‘,routes }) export default router main.js import Vue from ‘vue‘ import App from ‘./App.vue‘ import router from ‘./router‘ Vue.use(MintUI) Vue.use(ElementUI); Vue.config.productionTip = false new Vue({ router,render: h => h(App) }).$mount(‘#app‘) ? ? d、常规使用
<router-view></router-view>路由匹配到的组件将渲染在这里
你可以把他理解为一个版块,比如现在有一个home页面,分为两部分,内容部分和ibar部分,如图:
这五个页面共用下面的导航栏,只有导航栏上面的内容不同
<router-view></router-view>就可以写在<Ibar></Ibar>的上面
<template> <div class="home"> <router-view></router-view> <Ibar></Ibar> </div> </template> 那么在Ibar页面中如何切换路由呢? <template>
<div class="ibar">
<router-link to="/ho/home" tag="span" active-class="active">首页</router-link>
<router-link to="/ho/type" tag="span" active-class="active">类别</router-link>
<router-link to="/ho/need" tag="span" active-class="active">需求</router-link>
<router-link to="/ho/find" tag="span" active-class="active">发现</router-link>
<router-link to="/ho/mine" tag="span" active-class="active">我的</router-link>
</div>
</template>
注意:此处的tag=“span”代表这个按钮是个span标签,你可以写样式的时候直接写span标签的样式即可 此处的active-class="active"代表点击哪个按钮哪个按钮高亮
此时我们详细看一下router文件夹下的index.js //引入vue mode: ‘history‘, 引申1: 路由有一个meta属性 可以给该路由挂载一些信息 设置一些自己title、显示隐藏、左右滑动的方向之类的 meta: { title: "HelloWorld",要现实的title show: true 设置导航隐藏显示 } 使用的时候:this.$route.meta.show ? 引申2: 动态路由 { path:"/two/:id",component:Two,} 获取数据this.$route.params.动态路由的名字 此处是:this.$route.params.id ? 引申3: 路由别名alias { path: ‘/a‘,component: A,alias: ‘/b‘ } ? ? 2、react-router @4用法 a、大概目录 ? ? ? 不需要像vue那样麻烦的用到一个单独的文件夹,react只需要在index.js中部分配置即可? ? b、准备工作 ? yarn add react-router-dom ? index.js中 ??import { BrowserRouter } from ‘react-router-dom‘ ??
? ? ? ? ? <BrowserRouter>
? ? ? ? ? <App />
? ? ? ? ? </BrowserRouter>
这样App内部组件都可以使用
?
c、使用
? ? ?同样是上面那个例子,写法不一样:
import React,{ Component } from ‘react‘; import {Bar} from ‘components/common/ibar‘ import ShopDetail from ‘pages/shopDetail/shopDetail‘ import NodeDe from ‘pages/noteDetail/NodeDe‘ import Car from ‘pages/car/Car‘ import Admin from ‘pages/admin/Admin‘ import Admin1 from ‘pages/admin/Admin1‘ import GoodDetail from ‘pages/goodDetail/goodDetail‘ import { Route,Switch,Redirect } from ‘react-router-dom‘ class App extends Component { render() { return ( ? 当点击哪里需要跳转的时候,在标签外面包一个<Link to= ‘ 路由路径 ‘ ></Link> ? ? ? ? ? ? ? ? ?? 动态路由/xxx/:xx,如上图
引申1:HashRouter和BrowserRouter 它们两个是路由的基本,就像盖房子必须有地基一样 我们需要将它们包裹在最外层,我们只要选择其一就可以了。 现在讲它们的不同: HashRouter? 如果你使用过react-router2或3或者vue-router ? 你经常会发现一个现象就是url中会有个#, ? ? ? ? ? ? ? ? ?例如localhost:3000/# ? ? ? ? ? ? ? ? ?HashRouter就会出现这种情况,它是通过hash值来对路由进行控制 ? ? ? ? ? ? ? ? ?如果你使用HashRouter,你的路由就会默认有这个#。 ?? ? ?BrowserRouter? ? ? ? ? ? ? ? ?很多情况下我们则不是这种情况,我们不需要这个# ? 因为它看起来很怪,这时我们就需要用到BrowserRouter。 ? 引申2:Link和NavLink的选择 两者都是可以控制路由跳转的,不同点是NavLink的api更多,更加满足你的需求。 ? ? ?Link:主要api是to,to可以接受string或者一个object,来控制url
?NavLink:它可以为当前选中的路由设置类名、样式以及回调函数等。 ? ? ? ? ? ? ? 引申3:withRouter高阶组件 //引入withRouter
withRouter(GoodDetail)
withRouter(connect(mapState,mapDispatch)(GoodDetail))
? ? ? ? 3、什么是包容性路由?什么是排他性路由?
包容性路由: 如果路由有/food 和 /food/1 那么在匹配 /food 的时候两个都能匹配到 react就是典型的包容性路由 所以react需要引入Switch标签,把路由变成排他性的
排他性路由:? 只要匹配成功一个就不会往下面进行匹配了 vue是排他性路由 匹配从上到下,匹配到一个即止 ? ? 4、react路由有两个重要的属性:children和render,这两个有什么区别? a、Route 可以写行间render,render={()=>{return }}
?
b、也可以写行间children={()={return }}
?
c、不管匹配与否children都执行
?
d、render优先级比children高
?
5、react如何在路由里面定义一个子路由?
?
a、引入在需要子路由的页面引入Route标签
?
<Route path=‘/noteDetail/home‘ component={NodeDe} />
b、举个??(糖炒栗子,我的爱,为什么我自己做的??都那么难吃???)
? ? 我们在home页面里(左边一溜的父组件)该点击的地方 export const Home = () => (
<ul>
<li>
<NavLink to=‘/home‘ exact activeStyle ={selectedStyle}>首页</NavLink>
</li>
<li>
<NavLink to=‘/about‘ activeStyle ={selectedStyle}>关于我们</NavLink>
</li>
<li>
<NavLink to=‘/event‘ activeStyle ={selectedStyle}>企业事件</NavLink>
</li>
<li>
<NavLink to=‘/product‘ activeStyle ={selectedStyle}>公司产品</NavLink>
</li>
<li>
<NavLink to=‘/us‘ activeStyle ={selectedStyle}>联系我们</NavLink>
</li>
</ul>
)
? 我们在home页面里(左边一溜的父组件)设置内容应该不同的地方 <Redirect exact from="/" to="/home"></Redirect> <Route path=‘/home‘ exact component={Home}/> <Route path=‘/about‘ component={About}/> <Route path=‘/event‘ component={Event}/> <Route path=‘/product‘ component={Product}/> <Route path=‘/us‘ component={Us}/> ? 我们在关于我们页面该点击的地方 export const AboutMenu = () => (
<ul className="about-menu">
<li>
<NavLink to=‘/about‘ exact activeStyle ={selectedStyle}>公司简介</NavLink>
</li>
<li>
<NavLink to=‘/about/history‘ activeStyle ={selectedStyle}>公司历史</NavLink>
</li>
<li>
<NavLink to=‘/about/services‘ activeStyle ={selectedStyle}>公司服务</NavLink>
</li>
<li>
<NavLink to=‘/about/location‘ activeStyle ={selectedStyle}>企业位置</NavLink>
</li>
</ul>
)
我们在关于我们页面该实现内容不同的地方 <Route path=‘/about‘ exact component={Company}/> <Route path=‘/about/history‘ component={History}/> <Route path=‘/about/services‘ component={Services}/> <Route path=‘/about/location‘ component={Location}/> ? 由此便实现了react子路由 ? ? ? 6、vue如何在路由里面定义一个子路由? 给父路由加一个?children:[] 参考我的<1.d>的代码 const routes = [ { //path是路由的路径 path:‘/‘, //redirect代表重定向,因为当前路径‘/‘并没有对应的组件,所以需要重定向到其他路由页面 redirect:‘/ho‘ }, //当不需要重定向的时候,需要component写上当前路由对应的组件页面 component: Home, //有些路由还有子路由,需要用到children[], //当访问的时候,<router-link>的属性to的时候要把所有的父组件都带上 //如:此处的/ho/home/like children: [ ? ? 7、react怎么通过路由传参? a、通配符传参(刷新页面数据不丢失) //在定义路由的时候 <Route path=‘/path/:自己起个名字‘ component={Path}/> //在路由点击跳转的时候 <Link to="/path/你要传的参数">通配符</Link> //另一个页面接收传来的参数 this.props.match.params.你起的名字
? ? ?举个?? ? ? ? ? 另一个页面接收值的时候: this.props.match.params.id ? b、query传参(刷新页面数据丢失) //路由定义 <Route path=‘/query‘ component={Query}/> //跳转的时候 var query = { pathname: ‘/query‘,query: ‘我是通过query传值 ‘ } <Link to={query}>query</Link> //另一个页面使用的时候 this.props.location.query 这里的this.props.location.query === ‘我是通过query传值‘ ? c、state传参(刷新页面数据丢失,同query差不多,只是属性不一样,而且state传的参数是加密的,query传的参数是公开的)? //Route定义 <Link to={state}>state</Link> //使用的时候 var state = { pathname: ‘/state‘,state: ‘我是通过state传值‘ } <Route path=‘/state‘ component={State}/> //另一个页面获取值的时候 this.props.location.state 这里的this.props.location.state === ‘我是通过query传值‘ ? d、路由?传参数 ? ? ? ? ? ? ? 此处的foodmenu通过路由?后面传参数 ? 在另一个页面的this.props.location.search可以获取到 "?id=6"? ? ? 8、vue怎么通过路由传参? a、通配符传参数 //在定义路由的时候 { path: ‘/describe/:id‘,name: ‘Describe‘,component: Describe } //在使用的时候 this.$router.push({ path: `/describe/${id}`,}) //接收页面获取值 this.$route.params.id ? b、params传参,跳转的时候不会显示在url上 //在定义路由的时候 { path: ‘/describe‘,component: Describe } //在使用的时候 this.$router.push({ name: ‘Describe‘,params: { id: id } }) //接收页面获取值 this.$route.params.id ? c、query传参,传餐的时候在url显示? key=value & key=value //在定义路由的时候 { path: ‘/describe‘,component: Describe } //在使用的时候 this.$router.push({ path: ‘/describe‘,query: { id: id } }) //接收页面获取值 this.$route.query.id ? ? ? 9、怎么在react里拿到router对象? import withRouter 并且 export组件的时候,用withRouter把组件包起来 //引入withRouter import { Link,withRouter } from ‘react-router-dom‘ //代码结尾暴露的时候,把要暴露的组件包裹在withRouter中,做成一个高阶组件, //将react-router 的 history,match 三个对象传入 //将组件包一层withRouter,就可以拿到需要的路由信息 //获取路由信息的时候this.props.location withRouter(GoodDetail) withRouter(connect(mapState,mapDispatch)(GoodDetail)) ? ? ? 10、怎么在vue里拿到router对象? //在使用的时候 this.$router.push({ path: ‘/describe‘,query: { id: id } }) //接收页面获取值 this.$route.query.id ? ? 11、路由怎么回退? a、vue: b、react:this.props.history.goback() ? ? ? 12、react路由守卫? a、在之前的版本中,React Router 也提供了类似的? b、那么在react中如果我们也需要路由守卫怎么办?比如在跳转路由前需要判断用户是否登录?如果登录才可以进行跳转,否则没有权限 c、 //下面是我的实现方式, //首先,准备一份路由表, //包含了路由的地址,组件以及是否需要权限校验: import { HomePage } from ‘../pages/home/home.page‘; import { LoginPage } from ‘../pages/login/login.page‘; import { ErrorPage } from ‘../pages/error/error.page‘; interface routerConfigModel { path:string,component?:any,auth?:boolean } export const routerConfig:routerConfigModel[] = [ { path:‘/‘,component:HomePage,auth:true,},{ path:‘/home‘,{ path:‘/login‘,component:LoginPage,{ path:‘/404‘,component:ErrorPage } ]; //将 auth 设置为 true,表示该路由需要权限校验。 //然后,定义 Router 组件,该组件是经过高阶组件包装后的结果: import * as React from ‘react‘; import { HashRouter,Switch } from ‘react-router-dom‘; import { FrontendAuth } from ‘../components/frontend-auth/frontend-auth.component‘ import { routerConfig } from ‘./router.config‘ export class Router extends React.Component{ render(){ return( <HashRouter> <Switch> <FrontendAuth config={routerConfig} /> </Switch> </HashRouter> ); } } //所有的路由跳转,都交给 FrontendAuth 高阶组件代理完成。 //下面是 FrontendAuth 组件的实现: import * as React from ‘react‘; import { Route,Redirect } from ‘react-router-dom‘; import { propsModel } from ‘./frontend-auth.model‘ export class FrontendAuth extends React.Component<any,propsModel>{ render(){ const { location,config } = this.props; const { pathname } = location; const isLogin = localStorage.getItem(‘__config_center_token‘) // 如果该路由不用进行权限校验,登录状态下登陆页除外 // 因为登陆后,无法跳转到登陆页 // 这部分代码,是为了在非登陆状态下,访问不需要权限校验的路由 const targetRouterConfig = config.find((v:any) => v.path === pathname); if(targetRouterConfig && !targetRouterConfig.auth && !isLogin){ const { component } = targetRouterConfig; return <Route exact path={pathname} component={component} /> } if(isLogin){ // 如果是登陆状态,想要跳转到登陆,重定向到主页 if(pathname === ‘/login‘){ return <Redirect to=‘/‘ /> }else{ // 如果路由合法,就跳转到相应的路由 if(targetRouterConfig){ return <Route path={pathname} component={targetRouterConfig.component} /> }else{ // 如果路由不合法,重定向到 404 页面 return <Redirect to=‘/404‘ /> } } }else{ // 非登陆状态下,当路由合法时且需要权限校验时,跳转到登陆页面,要求登陆 if(targetRouterConfig && targetRouterConfig.auth){ return <Redirect to=‘/login‘ /> }else{ // 非登陆状态下,路由不合法时,重定向至 404 return <Redirect to=‘/404‘ /> } } } } //以及对应的 Model: export interface propsModel { config:any[],} //页面上的路由跳转,都由 FrontendAuth 高阶组件代理了, //在 Switch 组件内部,不再是 Route 组件, //而只有一个 FrontendAuth 组件。 //FrontendAuth 组件接收一个名为 config 的 Props,这是一份路由表。 //同时,由于 FrontendAuth 组件放在了 Switch 组件内部,React Router 还自动为 FrontendAuth 注入了 location 属性, //当地址栏的路由发生变化时,就会触发 location 属性对象上的 pathname 属性发生变化, //从而触发 FrontendAuth 的更新(调用 render 函数)。 //FrontendAuth 的 render 函数中, //根据 pathname 查找到路由表中的相关配置, //如果该配置中指定了无需校验,就直接返回相应的 Route 组件。 //如果查找到的配置需要进行校验,再根据是否登陆进行处理,具体可以查看代码中的注释。 总结一下,实现路由守卫需要考虑到以下的问题: 未登录情况下,访问不需要权限校验的合法页面:允许访问 登陆情况下,访问登陆页面:禁止访问,跳转至主页 登陆情况下,访问除登陆页以外的合法页面:允许访问 登陆情况下,访问所有的非法页面:禁止访问,跳转至 404 未登录情况下,访问需要权限校验的页面:禁止访问,跳转至登陆页 未登录情况下,访问所有的非法页面:禁止访问,跳转至 404 ? 13、vue路由守卫 a、beforeEach 全局守卫(每个路由调用前都会触发,根据from和to来判断是哪个路由触发) const router = new VueRouter({ ... }) router.beforeEach((to,from,next) => { // ... }) //每个守卫功能都有三个参数: //to: Route:导航到的目标Route对象 //from: Route:当前路线被导航离开 //next: Function:必须调用此函数来解析钩子 // next():继续前进到管道中的下一个钩子。如果没有留下挂钩,则确认导航。 // next(false):中止当前导航。如果浏览器URL已更改(由用户手动或通过后退按钮),则会将其重置为from路径的URL 。 // next(‘/‘)或next({ path: ‘/‘ }):重定向到其他位置。当前导航将中止,并将启动一个新导航。你可以通过任何位置对象next,它允许您指定类似的选项replace: true,name: ‘home‘在使用任何选项router-link的to道具或router.push // next(error):(2.4.0+)如果传递给的参数next是一个实例Error,导航将被中止,错误将传递给通过注册的回调router.onError()。 `
举个?? import Vue from ‘vue‘; import Router from ‘vue-router‘; import LoginPage from ‘@/pages/login‘; import HomePage from ‘@/pages/home‘; import GoodsListPage from ‘@/pages/good-list‘; import GoodsDetailPage from ‘@/pages/good-detail‘; import CartPage from ‘@/pages/cart‘; import ProfilePage from ‘@/pages/profile‘; Vue.use(Router) const router = new Router({ routes: [ { path: ‘/‘,// 默认进入路由 redirect: ‘/home‘ //重定向 },{ path: ‘/login‘,name: ‘login‘,component: LoginPage },{ path: ‘/home‘,name: ‘home‘,component: HomePage },{ path: ‘/good-list‘,name: ‘good-list‘,component: GoodsListPage },{ path: ‘/good-detail‘,name: ‘good-detail‘,component: GoodsDetailPage },{ path: ‘/cart‘,name: ‘cart‘,component: CartPage },{ path: ‘/profile‘,name: ‘profile‘,component: ProfilePage },{ path: ‘**‘,// 错误路由 redirect: ‘/home‘ //重定向 },] }); // 全局路由守卫 router.beforeEach((to,next) => { console.log(‘navigation-guards‘); // to: Route: 即将要进入的目标 路由对象 // from: Route: 当前导航正要离开的路由 // next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。 const nextRoute = [‘home‘,‘good-list‘,‘good-detail‘,‘cart‘,‘profile‘]; let isLogin = global.isLogin; // 是否登录 // 未登录状态;当路由到nextRoute指定页时,跳转至login if (nextRoute.indexOf(to.name) >= 0) { if (!isLogin) { console.log(‘what fuck‘); router.push({ name: ‘login‘ }) } } // 已登录状态;当路由到login时,跳转至home if (to.name === ‘login‘) { if (isLogin) { router.push({ name: ‘home‘ }); } } next(); }); export default router; ? ? b、beforeResolve(2.5.0新增) 全局解析守卫和类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用router.beforeEach ? c、 全局后置钩子router.afterEach((to,from) => { // ... }) //不会接受next函数也 //也不会改变导航本身 ? d、beforeEnter 路由独享的守卫const router = new VueRouter({ routes: [ { path: ‘/foo‘,component: Foo,beforeEnter: (to,next) => { // ... } } ] }) //与全局前置守卫的方法参数是一样的 ? e、 ? ? 组件内的守卫
const Foo = { template: `...`,beforeRouteEnter (to,next) { // 在渲染该组件的对应路由被 confirm 前调用 // 不!能!获取组件实例 `this` // 因为当守卫执行前,组件实例还没被创建 },beforeRouteUpdate (to,next) { // 在当前路由改变,但是该组件被复用时调用 // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候, // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。 // 可以访问组件实例 `this` },
//beforeRouteEnter守卫不能访问this, //因为守卫在导航确认前被调用,因此即将登场的新组件还没被创建。 //不过,可以你传通过一个回调给next来访问组件实例。 //在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数。 beforeRouteEnter (to,next) { next(vm => { // 通过 `vm` 访问组件实例 }) } 完整的导航解析流程
以上。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |