Vue-router

本文详细介绍了vue-router的基本概念、安装使用、简单路由配置、嵌套路由、路由传参的多种方式、编程式路由操作以及路由守卫的运用,包括全局、独享和组件级别的守卫。同时讨论了hash模式和history模式的区别与应用场景。
摘要由CSDN通过智能技术生成

一、概念

vue-router是Vue.js官方的路由插件,它和vue.js是深度集成的,适合用于构建单页面应用。vue的单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来。传统的页面应用,是用一些超链接来实现页面切换和跳转的。在vue-router单页面应用中,则是路径之间的切换,也就是组件的切换。路由模块的本质 就是建立起url和页面之间的映射关系。

(vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。路由实际上就是可以理解为指向,就是我在页面上点击一个按钮需要跳转到对应的页面,这就是路由跳转)

二、安装和使用

vue3
npm i vue-router
vue2
npm ivue-router@3
导入下载的vue-router,使用这个插件,并挂在vm的router上
main.js

import Vue from 'vue'
import App from './App.vue'
import VueRouter from "vue-router"

import router from "./router/index.js"
Vue.config.productionTip = false
Vue.use(VueRouter)
new Vue({
  render: h => h(App),
  router,
}).$mount('#app')

三、简单路由

新建一个router文件夹,把路由配置文件放到index.js里
创建需要的组件导入,用导入的vue-router方法实例化对象,在对象
里设置routes这个对象数组,对象数组里设置path和component
以及path带“/”,子级不带。

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';
import detail2 from "../pages/detail2.vue";
import test1 from "../pages/t1.vue"
const Router= new VueRouter({
    routes:[
        {
            path:"/about",
            component:About,
        },
        {
            path:"/home",
            component:Home,
        },
    ]
})

export default Router

在需要跳转的组件里配置路由跳转标签

 <router-link class="list-group-item "  active-class="active" to="/about">
 about
 </router-link> 
 <!--replace这次点击替换上一次-->
 <router-link class="list-group-item "  active-class="active" to="/home">
 home
 </router-link>

router标签解析后会变成a标签,根据to属性写的路径决定跳转,
active-class是显示当前路径是否包括to里的指向组件的路径,直观感受当前组件是否
显示,如果显示则该类激活。

 <router-view></router-view>

还有个给路由组件展示的标签

四、嵌套路由

设计到一个children属性
在路由表里面设置

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';
import detail2 from "../pages/detail2.vue";
import test1 from "../pages/t1.vue"
const Router= new VueRouter({
    mode:"history",
    routes:[
        {
            name:"aboutroute",
            path:"/about",
            component:About,
        },
        {
            name:"homeroute",
            path:"/home",
            component:Home,
            children:[
                {
                    name:"NEWS",
                    path:"news",
                    component:News,
                },
                {
                    name:"messageroute",
                    path:"message",
                    component:Message,
                }
            ]
        },
    ]
})
export default Router

这里将home对应的子路由设置在home的children下,涉及到一个新属性name,
用来简化路径的和设计后面传参的,在多级路由的时候可以使用name来跳转

 <router-link  class=" list-group-item" active-class="active" :to="{name:'messageroute'}">
 message
 </router-link>
 
  <router-link class=" list-group-item" active-class="active" to="/home/news">
  news
  </router-link>

五、路由传参

1、模板字符串传参

<router-link class="list-group-item" :to="`/home/message/detail?id=${m.id}&title=${m.title}`">
           {{ m.title }}
</router-link>

?跟的是需要传的参数,利用es6里面的模板字符串可以传变量的特性

2、query传参

vm和vc都可以访问自己独特的route属性,这个route属性里面有个query对象属性可以接受跳转过来的组件携带参数,这样想列表或者可以复用数据的组件可以很好的利用

<router-link class="list-group-item" :to="{
              name:'detailroute',
              query:{
                id:m.id,
                title:m.title
              }
            }">
            {{ m.title }}
 </router-link>

读取

<li>消息标题:{{ $route.query.title }}</li>

这里的对象也可以写path

3、params传参

vm这个route属性里面有个params对象属性可以接受跳转过来的组件携带参数
params只能用name

<router-link class="list-group-item" :to="{
          name:'detail2route',
         params:{
         id:news.id,
         title:news.title
         }
        }">
        {{ news.title }}
        </router-link>

读取

  <li>消息标题:{{ $route.params.title }}</li>

4、props属性的开启方式

(1)对象形式

  children:[
                        {
                            name:"detailroute",
                            path:"detail",
                            component:Detail,
                            props:{a:1,b:"h1"}
                        }
                    ]

这个用的很了解一下

(2)布尔值形式(仅限params)

  children:[
                        {
                            name:"detailroute",
                            path:"detail",
                            component:Detail,
                            props:true
                        }
                    ]

这样会使得所有传给这个组件的params参数作为props传给这个组件

(3)函数形式

 props({query:{id,title}}){//两层解构赋值
                            return {id,title}
                            },

这里通过 return 返回的值来发送props,这个函数可以得到route参数,通过解构赋值能很好的传参,做到query的props

接收就和普通的props接收一模一样

props:["id"]

六、编程式路由

1、replace和push

这个路由的历史纪录是压栈式,如果你用的是push历史记录会一直进到一个栈里
如果是replace模式会使得这次浏览记录替换上一次的浏览记录
默认是push

 <router-link class=" list-group-item" active-class="active" to="/home/news" replace>
 news
 </router-link>

2、非router-link跳转

router-link默认被浏览器解析成a标签,有时候不符合我的需求
这时候只需要在我们需要跳转地方添加相应的事件如点击事件
绑定相应的回调里面有这个方法执行就好

 methods:{
      pushShow(m){
        this.$router.push({
          name:"detailroute",
          query:{
                id:m.id,
                title:m.title
              }
        })
      },
      replaceShow(m){
        this.$router.replace({
          name:"detailroute",
          query:{
                id:m.id,
                title:m.title
              }
        })
      }
    }

七、缓存路由和路由特有的钩子

1、缓存路由

由于路由跳转后原来的路由就被销毁了,我们在表格填写的信息没有提交的话就一起消失了,为了避免这种情况,设置了缓存路由
被标签包住的就可以不被销毁

 <keep-alive include="news"> 
  <!---这里发include放的是组件名 也可以放几个: :include="['news','message']" 不写就全缓存-->
      <router-view></router-view>
</keep-alive>

2、路由特有的钩子


 <h1 :style="{opacity:opacity}">学习Vue是一个长期的事情</h1>


activated(){//路由组件独有的,被激活的生命周期
      this.timer=setInterval(() => {
        this.opacity-=0.01
        if(this.opacity<=0){
          this.opacity=1
        }
        console.log("run")
      }, 40);
    },
    deactivated(){//路由组件独有的,被切换走的生命周期
      clearInterval(this.timer)
    }

设置了缓存之后组件跳转后不会销毁,这时候用mounted,beforeDestory不在合适

八、路由守卫

1、全局路由守卫

(1)前置路由守卫

//全局前置路由守卫,初始化和切换前调用
Router.beforeEach((to,from,next)=>{
   if(to.meta.isAuth){
    if(localStorage.getItem("school")=='hy'){
        next()
    } 
    else{
        alert("学校名不对")
    }
   }
   else{
    next()
   }
})

前置路由守卫是指在路由发生跳转时路由对用户的验证,查看用户是否有权限访问这个组件,用next()决定是否访问
这个meta是路由表的一个属性,叫做元数据,因为路由表的属性都是固定的,不可随便更改,故我们要加信息在路由表里都设置在meta里
例如我设置是否要验证的属性isAuth

 children:[
                        {
                            name:"detail2route",
                            path:"detail2/:id/:title",
                            component:detail2,
                            props:true, //所有的params传参数作为props传到组件。
                            meta:{
                                title:"详情2"
                            },
                        },
                        {
                            path:"test1",
                            name:" test1",
                            component:test1,
                            meta:{
                                title:"测试1"
                            },
                        }
                    ],
                    meta:{
                        isAuth:true,
                        title:"新闻"
                    }
                },
                {
                    name:"messageroute",
                    path:"message",
                    component:Message,
                    children:[
                        {
                            name:"detailroute",
                            path:"detail",
                            component:Detail,
                            //改对象的key-value会以props的形式传给组件,只适用于params
                            // props:{a:1,b:"h1"}
                            props({query:{id,title}}){//两层解构赋值
                            return {id,title}
                            },
                            meta:{
                                title:"详情1"
                            }
                        }
                    ]

(2)后置的路由守卫

//后置守卫在初始化和切换后被调用了
Router.afterEach((to,from)=>{
    document.title=to.meta.title|| "demo"
})

2、独享路由守卫

全局的是每次路由跳转都要检查,也是写在路由表外面,
独享是写在对应的路由表里面,只检查对应的路由表

 {
                    name:"NEWS",
                    path:"news",
                    component:News,
                    beforeEnter:(to,from,next)=>{
                        console.log("独享路由守卫被使用")
                        next()
                    }
 }

独享只有一种守卫

3、组件守卫

要注意的是这个beforeRouterLeave是下一次跳转的时候才触发的

  beforeRouteEnter(to,from,next){
      console.log("about的组件路由守卫被触发")
      next()
    },
     beforeRouteLeave(to,from,next){
      console.log("about下一次离开被调用")
      next()
    }

九、hash模式和history模式

在路由表的对象里可以设置mode属性

const Router= new VueRouter({
    mode:"history",
    routes:[
        {
            name:"aboutroute",
            path:"/about",
            component:About,
            meta:{
                title:"关于"
            }
        }
        ]

history模式下就是简单的网址加路由路径
默认是hash模式,下面是网址加/#/加路由路径
一般来说hash的兼容性更好,因为服务器不会处理/#/(hash符号)后年的哈希值(是前端的hash值和加密无关)
如果是history模式下,因为发网络请求网址直接带着路由路径,而服务器里没有相应的资源,会出现得不到的现象。
当然借助后端插件或者正则都可以解决
比如在npm网站里的
link
就是输入npm install --save connect-history-api-fallback
然后使用就history没问题
hash对于一些手机app会认为非法。

十、样例源码分享

public/index.js

<!DOCTYPE html>
<html lang="">
 <head>
   <meta charset="utf-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width,initial-scale=1.0">
   <link rel="icon" href="<%= BASE_URL %>favicon.ico">
   <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" >
   <title><%= htmlWebpackPlugin.options.title %></title>
 </head>
 <body>
   <noscript>
     <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
   </noscript>
   <div id="app"></div>
   <!-- built files will be auto injected -->
 </body>
</html>

上面的直接引用bootstarp

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";
import Detail from '../pages/Detail.vue';
import detail2 from "../pages/detail2.vue";
import test1 from "../pages/t1.vue"
const Router= new VueRouter({
    mode:"history",
    routes:[
        {
            name:"aboutroute",
            path:"/about",
            component:About,
            meta:{
                title:"关于"
            }
        },
        {
            name:"homeroute",
            path:"/home",
            component:Home,
            meta:{
                title:"主页"
            },
            children:[
                {
                    name:"NEWS",
                    path:"news",
                    component:News,
                    beforeEnter:(to,from,next)=>{
                        console.log("独享路由守卫被使用")
                        next()
                    },
                    children:[
                        {
                            name:"detail2route",
                            path:"detail2/:id/:title",
                            component:detail2,
                            props:true, //所有的params传参数作为props传到组件。
                            meta:{
                                title:"详情2"
                            },
                        },
                        {
                            path:"test1",
                            name:" test1",
                            component:test1,
                            meta:{
                                title:"测试1"
                            },
                        }
                    ],
                    meta:{
                        isAuth:true,
                        title:"新闻"
                    }
                },
                {
                    name:"messageroute",
                    path:"message",
                    component:Message,
                    children:[
                        {
                            name:"detailroute",
                            path:"detail",
                            component:Detail,
                            //改对象的key-value会以props的形式传给组件,只适用于params
                            // props:{a:1,b:"h1"}
                            props({query:{id,title}}){//两层解构赋值
                            return {id,title}
                            },
                            meta:{
                                title:"详情1"
                            }
                        }
                    ],
                    meta:{
                        isAuth:true,
                        title:"消息"
                    }
                }
            ]
        },
    ]
})
//全局前置路由守卫,初始化和切换前调用
Router.beforeEach((to,from,next)=>{
   if(to.meta.isAuth){
    if(localStorage.getItem("school")=='hy'){
        next()
    } 
    else{
        alert("学校名不对")
    }
   }
   else{
    next()
   }
})
//后置守卫在初始化和切换后被调用了
Router.afterEach((to,from)=>{
    document.title=to.meta.title|| "demo"
})
export default Router

main.js

import Vue from 'vue'
import App from './App.vue'
import VueRouter from "vue-router"

import router from "./router/index.js"
Vue.config.productionTip = false
Vue.use(VueRouter)
new Vue({
  render: h => h(App),
  router,
}).$mount('#app')



components/banner.vue

<template>
   <div class="col-xs-offset-2 col-xs-8">
            <div class="page-header">
                <h2>Vue Router Demo</h2>
                <button @click="back">后退</button>
                <button @click="forward">前进</button>
            </div>
        </div>
</template>

<script>
export default {
    name:"banner",
    methods:{
        forward(){
            this.$router.forward()
        },
        back(){
            this.$router.back()
        }
    }
}
</script>

<style>

</style>

pages/about.vue

<template>
  <div>
    <h2>这是about</h2>
  </div>
</template>

<script>
export default {
    name:"about",
    //由路由规则的进入组件之前调用,组件路由守卫
    beforeRouteEnter(to,from,next){
      console.log("about的组件路由守卫被触发")
      next()
    },
    beforeRouteLeave(to,from,next){
      console.log("about下一次离开被调用")
      next()
    }
}
</script>

<style>

</style>

pages/home

<template>
  <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="{name:'messageroute'}">message</router-link>
        </li>
      </ul>
     <keep-alive include="news">  <!---这里发include放的是组件名 也可以: :include="['news','message']"-->
      <router-view></router-view>
     </keep-alive>
    </div>
  </div>
</template>

<script>

export default {
    name:"home"
}
</script>

<style>

</style>

page/message

<template>
  <div>
    <ul>
        <li v-for="m in messagelist" :key="m.id">
            <!-- <router-link class="list-group-item" :to="`/home/message/detail?id=${m.id}&title=${m.title}`">
            {{ m.title }}
            </router-link> -->
            <router-link class="list-group-item" :to="{
              name:'detailroute',
              query:{
                id:m.id,
                title:m.title
              }
            }">
            {{ m.title }}
            </router-link>
            <button @click="pushShow(m)">push查看</button>
            <button @click="replaceShow(m)">replace查看</button>
        </li>
    </ul>
    <router-view></router-view>
  </div>
</template>

<script>

export default {
    name:"message",
    data(){
      return {
        messagelist:[
          {id:"001",title:"消息1"},
          {id:"002",title:"消息2"},
          {id:"003",title:"消息3"}
        ]
      }
    },
    methods:{
      pushShow(m){
        this.$router.push({
          name:"detailroute",
          query:{
                id:m.id,
                title:m.title
              }
        })
      },
      replaceShow(m){
        this.$router.replace({
          name:"detailroute",
          query:{
                id:m.id,
                title:m.title
              }
        })
      }
    }

}
</script>

<style>

</style>

pages/news

<template>
  <div>
      <ul>
        <h1 :style="{opacity:opacity}">学习Vue是一个长期的事情</h1>
        <li v-for="news in newslist" :key="news.id">
        <router-link class="list-group-item" :to="{
          name:'detail2route',//params只能用name
         params:{
         id:news.id,
         title:news.title
         }
        }">
        <!-- <router-link class="list-group-item" :to="`/home/news/detail2/${news.id}/${news.title}`"> -->
        {{ news.title }}
        </router-link>
        <input type="text" >
        </li>     
      </ul>
      <router-view></router-view>
    </div>
  </template>
  
  <script>
  export default {
      name:"news",
      data(){
      return {
        newslist:[
          {id:"001",title:"新闻1"},
          {id:"002",title:"新闻2"},
          {id:"003",title:"新闻3"}
        ], 
        opacity:1
      }
    },
   /*mounted(){
      this.timer=setInterval(() => {
        this.opacity-=0.01
        if(this.opacity<=0){
          this.opacity=1
        }
      }, 40);
    },
    beforeDestroy(){
      clearInterval(this.timer)
    }*/
    activated(){//路由组件独有的,被激活的生命周期
      this.timer=setInterval(() => {
        this.opacity-=0.01
        if(this.opacity<=0){
          this.opacity=1
        }
        console.log("run")
      }, 40);
    },
    deactivated(){//路由组件独有的,被切换走的生命周期
      clearInterval(this.timer)
    }

  }
  </script>
  
  <style>
  
  </style>

pages/Detail

<template>
  <ul>
    <li>消息编号:{{ id }}</li>
    <li>消息标题:{{ $route.query.title }}</li>
  </ul>
</template>

<script>
export default {
    name:"Detail",
    props:["id","title"],
    mounted(){
        console.log(this)
      }
}
</script>

<style>

</style>

pages/detail2

<template>
   <div>
    <ul>
      <li>消息编号:{{ id }}</li>
      <li>消息标题:{{ $route.params.title }}</li>
    </ul>
   </div>
  </template>
  
  <script>
  export default {
      name:"detaila",
      mounted(){
        console.log(this.$route)
      },
      props:["id","title"]
     }
  
  </script>
  
  <style>
  
  </style>

pages/t1.vue

<template>
<div>
  <h1> 测试成功!</h1>
</div>
</template>

<script>
export default {
name:"t1"
}
</script>

<style>

</style>

运行截图
在这里插入图片描述

开发者工具
在这里插入图片描述

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学徒在修行

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值