vue路由的理解
1路由理解
一个路由(route)就是一组映射关系(key-value),多个路由需要路由器(router)进行管理。前端路由中key是路径,value是组件
作用:设定访问路径,并将路径和组件映射起来(就是用于局部刷新页面,不需要请求服务器来切换页面)
2路由传参
有两种传参方式,第一种query传参 第二种params传参
query传参
1.字符串写法直接写在路径中拼接 ?+参数 ,
2.对象写法 ,把路径单独写,数据单独写
数据传递根据的是路由路径
<!-- 跳转并携带query参数,to的字符串写法 --> <router-link :to="/home/message/detail?id=666&title=你好">跳转</router-link> <!-- 跳转并携带query参数,to的对象写法 --> <!-- name:'detail' 可以写路由的name 也可以直接写路径 --> <router-link :to="{ path:'/home/message/detail', query:{ id:666, title:'你好' } }" >跳转</router-link>
组件接收数据用的是
$route.query
<template> <div> <h3>信息编号:{{ $route.query.id }}</h3> <h3>信息标题:{{ $route.query.title }}</h3> </div> </template> <script> export default { name: "Msgdata", }; </script> <style> </style>
当有多个需要传递的参数时,总在模板中写 $route.query, 肯定是不好的,这时候就需要路由中接收并包装一下
还可以在路由设置中进行获取然后再传递到组件 可以用到props,写在组件的路由中
routes:[ { path:'/about', component:About, }, { path:'/home', component:Home, children:[ //通过children配置子级路由 { name:'news' path:'news', //此处一定不要写:/news component:News }, { name:'message' path:'message',//此处一定不要写:/message component:Message, children: [ { path: 'msgdata', component: Msgdata, //在这里接收一下传来的参数,然后包装一下再传给组件 props($route){ return {id:$route.query.id,title:$route.query.title} } } ] } ]
子组件接收
<template> <div> <h3>信息编号:{{ id }}</h3> <h3>信息标题:{{ title }}</h3> </div> </template> <script> export default { name: "Msgdata", props: ["id", "title"], }; </script> <style> </style>
r o u t e r 和 router和 router和route的区别可去目录9查看
params传参
1.直接路径传递参数
在路径中直接加 引号内的东西都会当成字符处理,所以给to加上冒号让他解析成表达式,但是表达式没有以斜杠开头的,所以加上` 模板引号 又变成了字符串,然后用${}配合模板字符串。
<router-link :to="`/home/news/shownews/${n.id}/${n.name}`"> {{ n.name }} </router-link>
2.方式写成对象形式
必须写name不可以用path作为路径
<router-link :to="{ // 用params传递参数时用到他的对象写法中不可使用 path:'路径' name: 'shownews', params: { id: n.id, name: n.name, }, }" > {{ n.name }} </router-link>
组件使用时和query相似
<ul> <!-- query里面写数据 --> <li>编号{{ $route.params.id }}</li> <li>姓名{{ $route.params.name }}</li> </ul>
如果有很多数据需要用时,可以借助路由包装一下,只需要props的值为true
name: 'shownews', // params 写法先在路径中占位 path: 'shownews/:id/:name', component: ShowNews, // props的第二种写法 props为布尔值,会接收所有params参数 以props的形式传递给Detail组件 props: true
子组件接收
<template> <ul> <!-- query里面写数据 --> <li>编号{{ id }}</li> <li>姓名{{ name }}</li> </ul> </template> <script> export default { name: "ShowNews", props: ["id", "title"], }; </script>
params传参可以理解为 ajax 中的 post 请求方式,参数都是不可见的,但是有一个弊端,就是当页面刷新了是获取不到参数值。用 query 来传参,这种方式可以理解为是 ajax 中的 get 方法,参数是直接在 url 后面添加的,参数是可见的,可以解决页面刷新参数消失问题
3.声明式与编程式路由导航
点击链接切换组件,这就是导航,也可以称为路径导航。导航又分为两种:声明式和编程式
vue中的导航
1.声明式导航:我们在网页中点击链接实现网页的切换;在Vue项目中点击切换组件,这都属于声明式导航
2.编程式导航:通过调用API方法实现导航的方式叫做编程式导航,比如在普通的网页中我们会去掉用location.href跳转到新页面
vue-router中有五种编程式导航API:
this.$router.push('Hash地址') 跳转到指定Hash地址,且增加一条历史记录
this.$router.replace('Hash地址') 跳转到指定Hash地址,且替换掉当前历史记录
this.$router.go('Number') 在浏览器历史记录中前进或者后退(1、-1......) 如果超出上限的话,则原地不动
在实际开发中前进或者后退一个以上页面是不常使用的,所以vue-router为我们提供了以下俩种方法用来前进后退一个页面:
this.$router.back() 后退一个历史页面 this.$router.forward() 前进一个历史页面
react中的导航
1.声明式导航 【Link,NavLink】
声明式导航自己主要用到的是react中的两个路由组件【Link、NavLink】。其中Link组件的导航方式和HMTL中的a标签类似,在react将虚拟DOM渲染成真实DOM后,Link组件也被渲染成了a标签。
react中的路由懒加载方式(link方式)
import React, { Component,lazy,Suspense } from 'react'//导入了路由懒加载模块 import { Route,Redirect,Link} from 'react-router-dom' import Login from '../Login/index' const lazyComponent = lazy(() => import('../lazyComponent')); //使用路由懒加载的方式加载组件 export default class World extends Component { render() { return ( <div className='worldFrame'> {/* 使用路由 */} <ul> <li> <h1> {/*使用Link跳转,同时携带参数ID*/} <Link to={`/login/${id}`} className='red'>跳转到Login</Link> <br /> <Link to="/lazyComponent" className='red'>跳转到路由懒加载组件</Link> </h1> </li> </ul> <hr /> <ul> <li> {/*渲染路由组件Login到该位置,同时接收到路由参数ID*/} <Route path='/login/:id' component={Login}></Route> {/*重定向*/} <Redirect to='/'></Redirect> </li> <li> {/*使用路由懒加载的模块,路由组件未加载出来前会以Loading字符显示在页面中*/} <Suspense fallback={<h1 style={{color:'skyblue'}}>Loading...</h1>}> <Route path="/lazyComponent" component={lazyComponent}></Route> </Suspense> </li> </ul> <br /> </div> ) } }
NavLink方式相当于Link的加强版,主要的属性有:
activeClassName(string):设置选中样式,默认值为active
activeStyle(object):当元素被选中时,为此元素添加样式
exact(bool):为true时,只有当导致和完全匹配class和style才会应用
strict(bool):为true时,在确定为位置是否与当前URL匹配时,将考虑位置pathname后的斜线
isActive(func)判断链接是否激活的额外逻辑的功能2.编程式导航 【props, useHistory() , Route】
利用已注册路由组件的props
import { Route, Redirect, Switch, BrowserRouter } from 'react-router-dom'; import { Component } from 'react'; import Aside from './views/Aside'; import AsideTwo from './views/Aside/AsideTwo'; import AsideThree from './views/Aside/AsideThree'; export default class App extends Component { render(){ return ( <div className="App"> <BrowserRouter> <aside className='content'> <Switch> {/*注册路由组件*/} <Route path="/aside" component={Aside}></Route> <Route path="/aside2" component={AsideTwo}></Route> <Route path="/aside3" component={AsideThree}></Route> {/*重定向*/} <Redirect to='/aside'></Redirect> </Switch> </BrowserRouter> </div> ) } }
子组件通过接收父组件传参实现跳转
//函数组件 import './index.sass' export default function AsideTwo(props){ const changeLink = ()=>{ // console.log('@@@@@',props) props.history.push('/aside') } return( <> <h1>主要视图区</h1> <h3>主要展示区2</h3> <button onClick={changeLink}>跳转到/aside</button> </> ) }
//类组件 import { Component } from 'react' import './index.sass' export default class AsideThree extends Component{ changLink = ()=>{ this.props.history.push('/aside') console.log('MMMM',this.props); } render(){ return( <> <h1>主页面视图</h1> <h3>主要展示区1</h3> <button onClick={this.changLink}>跳转到/aside</button> </> ) } }
这种方法缺点就是使用时需要在已注册的路由组件中使用,如果该组件不是路由组件,则props对象中将不会有需要使用的路由参数(如果父组件没有给子组件传参,props会是一个空对象)
在没有注册路由的组件中使用编程式导航
利用useHistory() 钩子(hook)来做函数式组件的编程式导航(
该钩子函数只能用于函数组件
)import { useHistory } from 'react-router';//导入useHistory钩子 import { Button } from 'antd'; export default function Header(){ let history = useHistory() //将useHistory()钩子赋值给history方便使用 let programmingLink = function(){ history.push('/home')//点击按钮后使用push方法跳转到对应的路由位置 } return( <div className='header'> <div className='btns'> <Button type="primary" onClick={programmingLink} ghost>Dashed</Button> </div> </div> ) }
在类式组件中需要进行编程式跳转【使用Route组件的render属性】
import { Component } from 'react' import { Route } from 'react-router' export default class Footer extends Component { render () { return ( <> <Route render={({ history }) => (<button onClick={() => { history.push('/changLink') }}>点击更换路由</button>)} /> </> ) } }
该方法push进去的路由需要是已经在Route组件中注册的路由,如果路由未注册,则无法跳转
4路由守卫
路由守卫的作用 : 对路由进行权限管理,必须符合条件才能访问。
路由守卫有三种: 全局守卫、独享守卫、组件内守卫
全局守卫
有三个参数to:去哪个路径,from:从哪个路径里来,next:是个函数调用的时候next()放行
// 配置在实例对象外 初始化时调用,每次发生路由变化前调用 router.beforeEach((to,from,next)=>{ console.log('beforeEach',to,from) if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制 if(localStorage.getItem('school') === 'atguigu'){ //权限控制的具体规则 next() //放行 }else{ alert('暂无权限查看') // next({name:'guanyu'}) } }else{ next() //放行 } }) //全局后置守卫:初始化时执行、每次路由切换后执行 router.afterEach((to,from)=>{ console.log('afterEach',to,from) if(to.meta.title){ document.title = to.meta.title //修改网页的title }else{ document.title = 'vue_test' } })
独享守卫
放在需要进行权限设置的路由里面,参数语法和全局一样 当访问这个路径前才执行beforeEnter()
beforeEnter(to,from,next){ console.log('beforeEnter',to,from) if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制 if(localStorage.getItem('school') === 'atguigu'){ next() }else{ alert('暂无权限查看') // next({name:'guanyu'}) } }else{ next() } }
组件守卫
放在组件里和methods,components同级别 ,必须是通过路由规则进入该组件才可以调用
beforeRouteEnter(),beforeRouteLeave()
//进入守卫:通过路由规则,进入该组件时被调用 beforeRouteEnter (to, from, next) { }, //离开守卫:通过路由规则,离开该组件时被调用 beforeRouteLeave (to, from, next) { }