vue-rooter:是vue的一个插件库,专门用来实现SPA应用
什么是路由?
路由分类
后端路由
前端路由
注意:vue2中,要用vue-router的3版本,vue3中,要用vue-router的4版本,否则会报错
安装vue-router,命令:npm i vue-router
编写router配置项:src/router/index.js
//引入VueRouter
import VueRouter from 'vue-router'
//引入Luyou 组件
import About from '../components/About'
import Home from '../components/Home'
//创建router实例对象,去管理一组一组的路由规则
const router = new VueRouter({
routes:[
{
path:'/about',
component:About
},
{
path:'/home',
component:Home
}
]
})
//暴露router
export default router
实现切换(active-class可配置高亮样式)
<router-link active-class="active" to="/about">About</router-link>
Vue中借助router-link标签实现路由的切换 ,
to=“/xxx”
是展示的路径,active-class
是当你点击这个的时候可展示的高亮样式
指定展示位置
<router-view></router-view>
图示代码:
路由组件通常存放在pages
文件夹,一般组件通常存放在components
文件夹。
通过切换,“隐藏”了的路由组件,默认是被销毁掉的,需要的时候再去挂载。
所以切换的时候,路由组件一直是 销毁-挂载-销毁-挂载. … … …
每个组件都有自己的$route
属性,里面存储着自己的路由信息。
配置路由规则,使用children配置项:
routes:[
{
path:'/about',
component:About,
},
{
path:'/home',
component:Home,
children:[ //通过children配置子级路由
{
path:'news', //此处一定不要写:/news
component:News
},
{
path:'message',//此处一定不要写:/message
component:Message
}
]
}
]
跳转(要写完整路径):
<router-link to="/home/news">News</router-link>
src/router/index.js
配置路由器
// 该文件专门用于创建整个应用的路由器
import VueRouter from 'vue-router'
// 引入组件
import About from '../pages/About.vue'
import Home from '../pages/Home.vue'
import News from '../pages/News.vue'
import Message from '../pages/Message.vue'
// 创建并暴露一个路由器
export default new VueRouter({
routes:[
{
path:'/about',
component:About
},
{
path:'/home',
component:Home,
children:[
{
path:'news',
component:News,
},
{
path:'message',
component:Message,
}
]
},
]
})
src/pages/Home.vue
是在Home里面嵌套一个路由,就要在Home.vue里面写结构,里面的路由部分修改
<template>
<div>
<h2>我是Home的内容</h2>
<div>
<h2>Home组件内容</h2>
<div>
<ul class="nav nav-tabs">
<li>
<router-link class="list-group-item" active-class="active" to="/home/news" >News</router-link
>
</li>
<li>
<router-link class="list-group-item" active-class="active" to="/home/message" >Message</router-link>
</li>
</ul>
<router-view></router-view>
</div>
</div>
</div>
</template>
<script>
export default {
name: "Home",
mounted() {
console.log("Home组件挂载完毕了", this);
},
};
</script>
传递参数
<li v-for="m in messageList" :key="m.id">
<router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`">{{m.title}} </router-link>
</li>
加了
:
冒号,就把=
后面的东西当成js去解析,然后``就是模板字符串,$(m.id)
是js变量,可以解析出来
<!-- 跳转并携带query参数,to的字符串写法 -->
<router-link :to="/home/message/detail?id=666&title=你好">跳转</router-link>
<!-- 跳转并携带query参数,to的对象写法 -->
<router-link :to="{
path:'/home/message/detail',
query:{
id:m.id,
title:m.title
}
}">
{{m.title}}
</router-link>
接收参数:
去子组件里接收参数
$route.query.id
$route.query.title
关键代码:
作用:可以简化路由的跳转。
如何使用
给路由命名:
{
path:'/demo',
component:Demo,
children:[
{
path:'test',
component:Test,
children:[
{
name:'hello' //给路由命名
path:'welcome',
component:Hello,
}
]
}
]
}
简化跳转:
<!--简化前,需要写完整的路径 -->
<router-link to="/demo/test/welcome">跳转</router-link>
<!--简化后,直接通过名字跳转 -->
<router-link :to="{name:'hello'}">跳转</router-link>
<!--简化写法配合传递参数 -->
<router-link
:to="{
name:'hello',
// 简化前:path:'/home/message/detail',
query:{
id:666,
title:'你好'
}
}"
>跳转</router-link>
配置路由,声明接收params参数
{
path:'/home',
component:Home,
children:[
{
path:'news',
component:News
},
{
component:Message,
children:[
{
name:'xiangqing',
path:'detail/:id/:title', //使用占位符声明接收params参数
component:Detail
}
]
}
]
}
传递参数
<!-- 跳转路由并携带params参数,to的字符串写法 -->
<!-- <router-link :to="`/home/message/detail/${m.id}/${m.title}`">{{m.title}}</router-link> -->
<!-- 跳转路由并携带params参数,to的对象写法 -->
<router-link :to="{
name:'xiangqing',
params:{
id:m.id,
title:m.title
}
}">
{{m.title}}
</router-link>
**特别注意:**路由携带
params
参数时,若使用to
的对象写法,则不能使用path
配置项,必须使用name
配置!
接收参数:
$route.params.id
$route.params.title
作用:让路由组件更方便的收到参数
配置props写在 src/router/index.js 里
写法一:
值为对象,该对象中的所有key-value都会以props的形式传给Detail组件
缺点:这样值是死的
{
name:'xiangqing',
path:'detail/:id/:title',
component:Detail,
//第一种写法:props值为对象,该对象中所有的key-value的组合最终都会通过props传给Detail组件
props:{a:900,b:'hello'} // 不常用
}
写法二:
值为布尔值,若布尔值为真,就会把该路由组件收到的params参数,以props的形式传给Detail组件
缺点:query参数不能用这个
{
name:'xiangqing',
path:'detail/:id/:title',
component:Detail,
//第二种写法:props值为布尔值,布尔值为true,则把路由收到的所有params参数通过props传给Detail组件
props:true
}
写法三:
props值为函数,该函数返回的对象中每一组key-value都会通过props传给Detail组件
个人认为这个挺好
{
name:'xiangqing',
path:'detail/:id/:title',
component:Detail,
//第三种写法:props值为函数,该函数返回的对象中每一组key-value都会通过props传给Detail组件
props($route){
return {
id:$route.query.id,
title:$route.query.title
}
}
}
push
和replace
,push
是追加历史记录,replace
是替换当前记录。路由跳转时候默认为push
replace
模式:News
如果你用的是默认的push,你点击进入到下一个路由的时候可以返回到上一个路由
如果你用的是replace,你点击进入到下一个路由的时候,浏览器左上角不会有返回上一步
作用:不借助
实现路由跳转,让路由跳转更加灵活
主要是用
$router
的两个apipush
,replace
,来实现路由跳转
具体编码:
//$router的两个API
this.$router.push({
name:'xiangqing',
params:{
id:xxx,
title:xxx
}
})
this.$router.replace({
name:'xiangqing',
params:{
id:xxx,
title:xxx
}
})
// 点了以后浏览器的前进后退操作
this.$router.forward() //前进
this.$router.back() //后退
this.$router.go() //可前进也可后退,5前进5步,-3后退3步
作用:让不展示的路由组件保持挂载,不被销毁。
具体编码:
// 缓存一个用字符串
<keep-alive include="News">
<router-view></router-view>
</keep-alive>
// 缓存多个路由组件用 数组 (使用 `v-bind`)
<keep-alive :include="['News', 'Message']">
<router-view></router-view>
</keep-alive>
注意:缓存的名字是组件名!!!在需要被缓存组件的外侧包裹keep-alive!!!
activated
路由组件被激活时触发。 (从没有出现在你面前–>组件出现在你眼前)deactivated
路由组件失活时触发。你在News组件里有个有个一直循环变化透明度的文字,但是你想离开这个页面时让他不动了,相当于销毁,但是News里面的input输入框要保持缓存,又不能被销毁。这时用到激活
activated
和 失活deactivated
<template>
<div>
<ul>
<li :style="{ opacity }">欢迎学习Vue</li>
<li>news001 <input type="text" /></li>
<li>news002 <input type="text" /></li>
<li>news003 <input type="text" /></li>
</ul>
</div>
</template>
<script>
export default {
name: "News",
data() {
return {
opacity: 1,
};
},
/* beforeMount(){
console.log('News组件即将被销毁');
clearInterval(this.timer)
},
mounted() {
this.timer= setInterval(() => {
this.opacity -= 0.01;
if (this.opacity <= 0) this.opacity = 1;
}, 16);
}, */
activated() {
console.log('News组件被激活了');
this.timer = setInterval(() => {
this.opacity -= 0.01;
if (this.opacity <= 0) this.opacity = 1;
}, 16);
},
deactivated() {
console.log('News组件失活了');
clearInterval(this.timer)
},
};
</script>
作用:对路由进行权限控制(我想让你看哪个,不想让你看哪个)
分类:全局守卫、独享守卫、组件内守卫
路由元信息meta
全局前置守卫:初始化时执行、每次路由切换前执行
router.beforeEach((to,from,next)=>{ })
全局后置守卫:初始化时执行、每次路由切换后执行
router.afterEach((to,from)=>{ })
// src/router/index.js
//全局前置守卫:初始化时执行、每次路由切换前执行
router.beforeEach((to,from,next)=>{
console.log('beforeEach',to,from)
if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制
if(localStorage.getItem('school') === 'atguigu'){ //权限控制的具体规则
next() //放行
}else{
alert('暂无权限查看')
}
}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'
}
})
主要代码:
// 该文件专门用于创建整个应用的路由器
import VueRouter from 'vue-router'
// 引入组件
import About from '../pages/About.vue'
import Home from '../pages/Home.vue'
import News from '../pages/News.vue'
import Message from '../pages/Message.vue'
import Detail from '../pages/Detail.vue'
// 创建并暴露一个路由器
const router = new VueRouter({
routes: [
{
name: 'guanyu',
path: '/about',
component: About,
meta:{title:'关于'},
},
{
name: 'zhuye',
path: '/home',
component: Home,
meta:{title:'主页'},
children: [
{
name:'xinwen',
path: 'news',
component: News,
meta:{isAuth:true,title:'新闻'}, // 需要权限校验
},
{
name: 'xiaoxi',
path: 'message',
component: Message,
meta:{isAuth:true,title:'消息'}, // 需要权限校验
children: [
{
name: 'xiangqing',
path: 'detail/:id/:title',
meta:{isAuth:true,title:'详情'},
component: Detail,
// props的第一种写法:值为对象,该对象中的所有key-value都会以props的形式传给Detail组件
// props:{a:1,b:'hello'}
// props的第二种写法:值为布尔值,若布尔值为真,就会把该路由组件收到的params参数,以props的形式传给Detail组件
// props:true
// props的第三种写法:值为函数,
props($route) {
return {
id: $route.params.id,
title: $route.params.title
}
}
}
]
}
]
},
]
})
// 全局前置路由守卫-------初始化的时候、在每一次切换路由器之前,调用一个函数
router.beforeEach((to, from, next) => {
console.log('beforeEach','to', to);
console.log('beforeEach','from', from);
// if (to.path === '/home/news' || to.name === 'xiaoxi') {
if (to.meta.isAuth) { // 判断是否需要鉴定权限
if (localStorage.getItem('school') === 'atguigu') {
next()
}else{
alert('学校名不对,无权限')
}
}else{
next()
}
})
// 后置路由守卫-------初始化的时候、在每一次切换路由器之后,调用一个函数
router.afterEach((to,from)=>{
console.log('后置路由守卫',to,from);
if(to.meta.title){
document.title = to.meta.title
}else{
document.title = 'vue_test'
}
})
export default router
独享路由守卫:某一个路由单独享用的守卫
注意:独享路由只有beforeEnter,没有afterEnter
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()
}
}
在组件内写这个 组件内守卫,该组件独有的路由守卫
进入守卫:必须通过路由规则,写组件标签进入不行
离开守卫:你得触发路径的变化,前端浏览器监测到了才允许你离开
//进入守卫:通过路由规则,进入该组件时被调用
beforeRouteEnter (to, from, next) {
},
//离开守卫:通过路由规则,离开该组件时被调用
beforeRouteLeave (to, from, next) {
}
主要代码:
// src/pages/About.vue
<script>
export default {
name: "About",
mounted() {
console.log("About组件挂载完毕了", this.$route);
},
// 通过路由规则,进入该组件时被调用
beforeRouteEnter(to, from, next) {
// 当路由进入之前
if (to.meta.isAuth) {
// 判断是否需要鉴定权限
if (localStorage.getItem("school") === "atguigu") {
next();
} else {
alert("学校名不对,无权限");
}
} else {
next();
}
},
// 通过路由规则,离开该组件时被调用
beforeRouteLeave(to, from, next) {
// 当路由离开之前
console.log('beforeRouteLeave',to,from);
next() // 放行
},
};
</script>
hash值不会包含在 HTTP 请求中,即:hash值不会带给服务器。
hash模式:
路由器的默认工作模式是hash模式
npm run build
打包文件生成纯html css js 文件
这个文件必须放在服务器上部署才能看
解决history刷新报错的问题
后端安装中间件connect-history-api-fallback
这个插件可以帮助分辨是前端路由还是后端请求,从而避免报错