路由
编程式路由导航
Home.vue(去掉两个router-line的replace)
<template>
<div>
<h1>我是Home的内容</h1>
<br>
<div class="btn-group" role="group" aria-label="...">
<router-link type="button" class="btn btn-default" active-class="active" to="/home/news">News</router-link>
<router-link type="button" class="btn btn-default" active-class="active" to="/home/message">Message</router-link>
</div>
<br><br>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: "Home",
/*mounted(){
console.log("Home组件被挂载了")
window.homeRoute=this.$route
window.homeRouter=this.$router
},
beforeDestroy() {
console.log("Home组件被销毁了")
}*/
}
</script>
<style scoped lang="less">
</style>
HomeMessage.vue
<template>
<div>
<button @click="goTest(2)">go查看测试(前进2步)</button>
<ul>
<!-- 跳转路由并携带params参数,to的字符串的写法-->
<li v-for="m in messageList" :key="m.id">
<!-- <router-link :to="`/home/message/detail/${m.id}/${m.title}`">{{m.title}}</router-link>-->
<!-- 跳转路由并携带params参数,只能使用名字跳转,to的对象的写法-->
<router-link :to="{
name:'xiangqing',
query:{
id:m.id,
title:m.title
}
}">
{{m.title}}
</router-link>
<button @click="pushShow(m)">push查看</button>
<button @click="replaceShow(m)">replace查看</button>
<button @click="goTest(-3)">go查看测试(后退3步)</button>
<br>
</li>
</ul>
<hr>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: "HomeMessage",
data(){
return{
messageList:[
{id:"001",title:"消息001"},
{id:"002",title:"消息002"},
{id:"003",title:"消息003"},
]
}
},
methods:{
pushShow(m){
console.log(this.$router)
this.$router.push({
name:'xiangqing',
query:{
id:m.id,
title:m.title
}
})
},
replaceShow(m){
this.$router.replace({
name:'xiangqing',
query:{
id:m.id,
title:m.title
}
})
},
goTest(value){
this.$router.go(value)
}
}
}
</script>
<style scoped>
.active{
color: black;
}
</style>
Banner.vue
<template>
<div>
<h1>Vue Router Demo</h1>
<button @click="back()">后退</button>
<button @click="forward()">前进</button>
<br>
<br>
</div>
</template>
<script>
export default {
name: "Banner",
methods:{
back(){
this.$router.back()
},
forward(){
this.$router.forward()
}
}
}
</script>
<style scoped>
h1{
border-bottom: 1px solid #ccc;
}
</style>
总结
- 作用:不借助<router-link>实现路由跳转,让路由跳转更加灵活
- 具体编码:
//$router的两个API
this.$router.push({
name:'xiangqing',
query:{
id:m.id,
title:m.title
}
})
this.$router.replace({
name:'xiangqing',
query:{
id:m.id,
title:m.title
}
})
this.$router.back() //后退
this.$router.forward() //前进
this.$router.go(3) //可前进也可后退
- 补充一个$router的api:go
go函数的参数表示浏览器历史记录前进/后退几步(正数为前进,负数为后退)
缓存路由组件
Home.vue
<template>
<div>
<h1>我是Home的内容</h1>
<br>
<div class="btn-group" role="group" aria-label="...">
<router-link type="button" class="btn btn-default" active-class="active" to="/home/news">News</router-link>
<router-link type="button" class="btn btn-default" active-class="active" to="/home/message">Message</router-link>
</div>
<br><br>
<!-- include后面跟的是组件名-->
<keep-alive include="HomeNews">
<router-view></router-view>
</keep-alive>
</div>
</template>
<script>
export default {
name: "Home",
/*mounted(){
console.log("Home组件被挂载了")
window.homeRoute=this.$route
window.homeRouter=this.$router
},
beforeDestroy() {
console.log("Home组件被销毁了")
}*/
}
</script>
<style scoped lang="less">
</style>
HomeNews.vue
<template>
<div>
<ul>
<li>新闻001 <input type="text"></li>
<li>新闻002 <input type="text"></li>
<li>新闻003 <input type="text"></li>
</ul>
</div>
</template>
<script>
export default {
name: "HomeNews",
beforeDestroy() {
console.log("HomeNews组件即将被销毁")
}
}
</script>
<style scoped>
</style>
HomeMessage.vue
<template>
<div>
<ul>
<!-- 跳转路由并携带params参数,to的字符串的写法-->
<li v-for="m in messageList" :key="m.id">
<!-- <router-link :to="`/home/message/detail/${m.id}/${m.title}`">{{m.title}}</router-link>-->
<!-- 跳转路由并携带params参数,只能使用名字跳转,to的对象的写法-->
<router-link :to="{
name:'xiangqing',
query:{
id:m.id,
title:m.title
}
}">
{{m.title}}
</router-link>
<button @click="pushShow(m)">push查看</button>
<button @click="replaceShow(m)">replace查看</button>
<br>
</li>
</ul>
<hr>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: "HomeMessage",
data(){
return{
messageList:[
{id:"001",title:"消息001"},
{id:"002",title:"消息002"},
{id:"003",title:"消息003"},
]
}
},
methods:{
pushShow(m){
console.log(this.$router)
this.$router.push({
name:'xiangqing',
query:{
id:m.id,
title:m.title
}
})
},
replaceShow(m){
this.$router.replace({
name:'xiangqing',
query:{
id:m.id,
title:m.title
}
})
},
},
beforeDestroy() {
console.log("HomeMessage组件即将被销毁")
}
}
</script>
<style scoped>
.active{
color: black;
}
</style>
总结
- 作用:让不展示的路由组件保持挂载,不被销毁
- 具体编码:
<keep-alive include="HomeNews">
<router-view></router-view>
</keep-alive>
两个新的生命周期钩子
保留缓存组件功能后新增的需求
HomeNews.vue
<template>
<div>
<div :style="{opacity}">欢迎学习Vue</div>
<ul>
<li>新闻001 <input type="text"></li>
<li>新闻002 <input type="text"></li>
<li>新闻003 <input type="text"></li>
</ul>
</div>
</template>
<script>
export default {
name: "HomeNews",
data(){
return{
opacity: 1
}
},
activated() {
console.log("News组件被激活了")
this.timer=setInterval(()=>{
console.log("@")
this.opacity-=0.01
if(this.opacity<0) this.opacity=1
},16)
},
deactivated() {
console.log("News组件失活了")
clearInterval(this.timer)
}
}
</script>
<style scoped>
</style>
HomeMessage.vue
<template>
<div>
<ul>
<!-- 跳转路由并携带params参数,to的字符串的写法-->
<li v-for="m in messageList" :key="m.id">
<!-- <router-link :to="`/home/message/detail/${m.id}/${m.title}`">{{m.title}}</router-link>-->
<!-- 跳转路由并携带params参数,只能使用名字跳转,to的对象的写法-->
<router-link :to="{
name:'xiangqing',
query:{
id:m.id,
title:m.title
}
}">
{{m.title}}
</router-link>
<button @click="pushShow(m)">push查看</button>
<button @click="replaceShow(m)">replace查看</button>
<br>
</li>
</ul>
<hr>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: "HomeMessage",
data(){
return{
messageList:[
{id:"001",title:"消息001"},
{id:"002",title:"消息002"},
{id:"003",title:"消息003"},
]
}
},
methods:{
pushShow(m){
console.log(this.$router)
this.$router.push({
name:'xiangqing',
query:{
id:m.id,
title:m.title
}
})
},
replaceShow(m){
this.$router.replace({
name:'xiangqing',
query:{
id:m.id,
title:m.title
}
})
},
},
}
</script>
<style scoped>
.active{
color: black;
}
</style>
Home.vue
<template>
<div>
<h1>我是Home的内容</h1>
<br>
<div class="btn-group" role="group" aria-label="...">
<router-link type="button" class="btn btn-default" active-class="active" to="/home/news">News</router-link>
<router-link type="button" class="btn btn-default" active-class="active" to="/home/message">Message</router-link>
</div>
<br><br>
<!-- include后面跟的是组件名-->
<keep-alive include="HomeNews">
<router-view></router-view>
</keep-alive>
</div>
</template>
<script>
export default {
name: "Home",
/*mounted(){
console.log("Home组件被挂载了")
window.homeRoute=this.$route
window.homeRouter=this.$router
},
beforeDestroy() {
console.log("Home组件被销毁了")
}*/
}
</script>
<style scoped lang="less">
</style>
总结
- 作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。
- 具体名字
(1)activated路由组件被激活时触发
(2)deactivated路由组件失活时触发
全局路由守卫
路由前置守卫
src/router/index.js
//该文件专门用于创建整个应用的路由器
import VueRouter from "vue-router";
//引入组件
import About from "@/pages/About";
import Home from "@/pages/Home";
import HomeNews from "@/pages/HomeNews";
import HomeMessage from "@/pages/HomeMessage";
import Detail from "@/pages/Detail";
//创建并暴露一个路由器
const router=new VueRouter({
routes:[
{
name:'guanyu',
path:'/about',
component:About
},
{
name:"zhuye",
path:'/home',
component:Home,
children:[
{
name:'xinwen',
path:'news',
component:HomeNews
},
{
name:'xiaoxi',
path:'message',
component:HomeMessage,
children:[
{
name:'xiangqing',
// path:'detail/:id/:title', //nodejs的占位符,后面会填充内容
path:'detail', //query的写法
component:Detail,
//props的第一种写法,值为对象,该对象中的所有key-value都会以props的形式传给Detail组件
// props:{a:1,b:'你好啊'},
//props的第二种写法,值为布尔值,若布尔值为真,就会把该路由组件收到的所有params参数,以props的形式传给Detail组件
// props:true,
//props的第三种写法:函数式(最普通的写法)
/*props($route){
return {id:$route.query.id,title:$route.query.title}
}*/
//第三种:函数式(解构赋值的写法)
/*props({query}){
return{id:query.id,title:query.title}
}*/
//第三种:函数式(解构赋值之后再解构赋值)
props({query:{id,title}}){
return {id,title}
}
}
]
}
]
}
]
})
//全局前置路由守卫——初始化的时候被调用、每次路由切换之前被调用
router.beforeEach((to,from,next)=>{
console.log("to",to)
console.log("from",from)
if(to.name=="xinwen"||to.path=="/home/message"){
console.log(localStorage.getItem("school"))
if(localStorage.getItem("school")==="lucky"){
next()
}else{
alert("学校名字不对,无权限查看")
}
}else{
next()
}
})
export default router
路由后置守卫及用户鉴权问题
src/router/index.js
//该文件专门用于创建整个应用的路由器
import VueRouter from "vue-router";
//引入组件
import About from "@/pages/About";
import Home from "@/pages/Home";
import HomeNews from "@/pages/HomeNews";
import HomeMessage from "@/pages/HomeMessage";
import Detail from "@/pages/Detail";
//创建并暴露一个路由器
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:HomeNews,
meta:{isAuth:true,title:"新闻"}, //增加权限控制
},
{
name:'xiaoxi',
path:'message',
component:HomeMessage,
meta:{isAuth: true,title:"消息"},
children:[
{
name:'xiangqing',
// path:'detail/:id/:title', //nodejs的占位符,后面会填充内容
path:'detail', //query的写法
component:Detail,
meta:{isAuth: true,title:"详情"},
//props的第一种写法,值为对象,该对象中的所有key-value都会以props的形式传给Detail组件
// props:{a:1,b:'你好啊'},
//props的第二种写法,值为布尔值,若布尔值为真,就会把该路由组件收到的所有params参数,以props的形式传给Detail组件
// props:true,
//props的第三种写法:函数式(最普通的写法)
/*props($route){
return {id:$route.query.id,title:$route.query.title}
}*/
//第三种:函数式(解构赋值的写法)
/*props({query}){
return{id:query.id,title:query.title}
}*/
//第三种:函数式(解构赋值之后再解构赋值)
props({query:{id,title}}){
return {id,title}
}
}
]
}
]
}
]
})
//全局前置路由守卫——初始化的时候被调用、每次路由切换之前被调用
router.beforeEach((to,from,next)=>{
console.log("前置守卫",to,from)
// if(to.name=="xinwen"||to.path=="/home/message"){
if(to.meta.isAuth){ //判断是否需要鉴权
if(localStorage.getItem("school")==="lucky"){
next()
}else{
alert("学校名字不对,无权限查看")
}
}else{
next()
}
})
//全局后置路由守卫——初始化的时候被调用、每次路由切换之后被调用
router.afterEach((to,from)=>{
console.log("后置路由守卫",to,from)
document.title=to.meta.title||"xx系统"
})
export default router
总结
- 作用:对路由进行权限控制
- 分类:全局守卫、独享守卫、组件内守卫
- 全局守卫
//全局前置路由守卫——初始化的时候被调用、每次路由切换之前被调用
router.beforeEach((to,from,next)=>{
console.log("前置守卫",to,from)
if(to.meta.isAuth){ //判断是否需要鉴权(判断当前路由是否需要进行权限控制)
if(localStorage.getItem("school")==="lucky"){//权限控制的具体规则
next() //放行
}else{
alert("学校名字不对,无权限查看") //暂无权限
}
}else{
next() //放行
}
})
//全局后置路由守卫——初始化的时候被调用、每次路由切换之后被调用
router.afterEach((to,from)=>{
console.log("后置路由守卫",to,from)
if(to.meta.title){
document.title=to.meta.title||"xx系统" //修改网页的title
}else{
document.title="vue_test" //修改网页的title
}
})
export default router
独享路由守卫
src/router/index.js
//该文件专门用于创建整个应用的路由器
import VueRouter from "vue-router";
//引入组件
import About from "@/pages/About";
import Home from "@/pages/Home";
import HomeNews from "@/pages/HomeNews";
import HomeMessage from "@/pages/HomeMessage";
import Detail from "@/pages/Detail";
//创建并暴露一个路由器
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:HomeNews,
meta:{isAuth:true,title:"新闻"}, //增加权限控制
//独享前置路由守卫(只有前置)
beforeEnter:(to, from, next)=>{
if(to.meta.isAuth){ //判断是否需要鉴权
if(localStorage.getItem('school')==='lucky'){
next()
}else{
alert("学校名不对,无权限查看!")
}
}else{
next()
}
}
},
{
name:'xiaoxi',
path:'message',
component:HomeMessage,
meta:{isAuth: true,title:"消息"},
children:[
{
name:'xiangqing',
// path:'detail/:id/:title', //nodejs的占位符,后面会填充内容
path:'detail', //query的写法
component:Detail,
meta:{isAuth: true,title:"详情"},
//props的第一种写法,值为对象,该对象中的所有key-value都会以props的形式传给Detail组件
// props:{a:1,b:'你好啊'},
//props的第二种写法,值为布尔值,若布尔值为真,就会把该路由组件收到的所有params参数,以props的形式传给Detail组件
// props:true,
//props的第三种写法:函数式(最普通的写法)
/*props($route){
return {id:$route.query.id,title:$route.query.title}
}*/
//第三种:函数式(解构赋值的写法)
/*props({query}){
return{id:query.id,title:query.title}
}*/
//第三种:函数式(解构赋值之后再解构赋值)
props({query:{id,title}}){
return {id,title}
}
}
]
}
]
}
]
})
//全局后置路由守卫——初始化的时候被调用、每次路由切换之后被调用
router.afterEach((to,from)=>{
console.log("后置路由守卫",to,from)
document.title=to.meta.title||"xx系统"
})
export default router
总结
- 独享守卫
//独享前置路由守卫(只有前置)
beforeEnter(to, from, next){
if(to.meta.isAuth){ //判断当前路由是否需要权限控制
if(localStorage.getItem('school')==='lucky'){
next()
}else{
alert("学校名不对,无权限查看!")
}
}else{
next()
}
}
组件内路由守卫
src/router/index.js(改了about的用户鉴权)
//该文件专门用于创建整个应用的路由器
import VueRouter from "vue-router";
//引入组件
import About from "@/pages/About";
import Home from "@/pages/Home";
import HomeNews from "@/pages/HomeNews";
import HomeMessage from "@/pages/HomeMessage";
import Detail from "@/pages/Detail";
//创建并暴露一个路由器
const router=new VueRouter({
routes:[
{
name:'guanyu',
path:'/about',
component:About,
meta:{isAuth:true,title:"关于"},//设置权限
},
{
name:"zhuye",
path:'/home',
component:Home,
meta:{title:"主页"},
children:[
{
name:'xinwen',
path:'news',
component:HomeNews,
meta:{isAuth:true,title:"新闻"}, //增加权限控制
//独享前置路由守卫(只有前置)
beforeEnter:(to, from, next)=>{
if(to.meta.isAuth){ //判断是否需要鉴权
if(localStorage.getItem('school')==='lucky'){
next()
}else{
alert("学校名不对,无权限查看!")
}
}else{
next()
}
}
},
{
name:'xiaoxi',
path:'message',
component:HomeMessage,
meta:{isAuth: true,title:"消息"},
children:[
{
name:'xiangqing',
// path:'detail/:id/:title', //nodejs的占位符,后面会填充内容
path:'detail', //query的写法
component:Detail,
meta:{isAuth: true,title:"详情"},
//props的第一种写法,值为对象,该对象中的所有key-value都会以props的形式传给Detail组件
// props:{a:1,b:'你好啊'},
//props的第二种写法,值为布尔值,若布尔值为真,就会把该路由组件收到的所有params参数,以props的形式传给Detail组件
// props:true,
//props的第三种写法:函数式(最普通的写法)
/*props($route){
return {id:$route.query.id,title:$route.query.title}
}*/
//第三种:函数式(解构赋值的写法)
/*props({query}){
return{id:query.id,title:query.title}
}*/
//第三种:函数式(解构赋值之后再解构赋值)
props({query:{id,title}}){
return {id,title}
}
}
]
}
]
}
]
})
//全局前置路由守卫——初始化的时候被调用、每次路由切换之前被调用
/*router.beforeEach((to,from,next)=>{
console.log("前置守卫",to,from)
// if(to.name=="xinwen"||to.path=="/home/message"){
if(to.meta.isAuth){ //判断是否需要鉴权
if(localStorage.getItem("school")==="lucky"){
next()
}else{
alert("学校名字不对,无权限查看")
}
}else{
next()
}
})*/
//全局后置路由守卫——初始化的时候被调用、每次路由切换之后被调用
router.afterEach((to,from)=>{
// console.log("后置路由守卫",to,from)
document.title=to.meta.title||"xx系统"
})
export default router
About.vue
<template>
<h1>我是About的内容</h1>
</template>
<script>
export default {
name: "About",
/*mounted(){
console.log("About组件被挂载了",this)
window.aboutRoute=this.$route
window.aboutRouter=this.$router
},
beforeDestroy() {
console.log("About组件被销毁了")
}*/
//通过路由规则,进入该组件时被调用
beforeRouteEnter(to,from,next){
console.log("About-beforeRouteEnter",to,from)
if(to.meta.isAuth){
if(localStorage.getItem("school")=="lucky"){
next()
}else{
alert("学校名不对,无权限查看")
}
}else{
next()
}
},
//通过路由规则,离开该组件时被调用
beforeRouteLeave(to,from,next){
console.log("About--beforeRouteLeave",to,from)
next()
}
}
</script>
<style scoped>
</style>
总结
组件内守卫:
//进入守卫,通过路由规则,进入该组件时被调用
beforeRouteEnter(to,from,next){
},
//离开守卫,通过路由规则,离开该组件时被调用
beforeRouteLeave(to,from,next){
}