前端路由和vue-router

1. 前端路由的概念与原理

1.1 什么是路由

路由 Router 就是对应关系

1.2 SPA 与前端路由

SPA:

SPA 指的是一个 web 网站只有唯一的一个 HTML 页面,所有的组件的展示与切换都在这唯一的一个页面内完成。此时,不同的组件之间的切换需要通过前端路由来实现。

前端路由:

Hash 地址组件之间的对应关系

1.3 锚链接

  • 页面不会刷新
  • 会导致浏览历史

location.hash 可访问到当前hash 地址

location.href 可访问到当前全部地址

1.4 前端路由工作方式

  • 用户点击了页面上的路由链接
  • 导致了 URL 地址栏中的 Hash 值发生变化
  • 前端路由监听到了 Hash 地址的变化
  • 前端路由把当前 Hash 地址对应的组件渲染到浏览器中

1.5 手动模拟简易的前端路由

  • 通过动态组件<component>,指定当前渲染的组件

  • 通过监听 window.onhashchange 事件,当hash 地址发生变化,会触发当前事件

  • 通过 location.hash 访问到当前hash 地址,转存到data节点的 comName变量下

  • comName 变量是字符串,是动态组件<component>is 属性值,默认为 Left

  • 当 App 根组件一被创建就监听window.onhashchange事件,在 created 声明周期

案例源码:

App.vue

<template>
    <div class="outer">
        <div class="text-box">
            <h1> App.vue 根组件</h1>
            <a href="#/left">Left</a> 
            <a href="#/right">Right</a>
        </div>
        <hr>
        <component :is="comName"></component>
    </div>
</template>

<script>
// 1.导入需要使用的 Vue 组件
import Left from '@/components/Left.vue'
import Right from '@/components/Right.vue'

// 默认导出 固定写法
export default {
    components: {
        Left,
        Right,
    },
    data() {
        return {
            // 在动态组件的位置要展示的组件的名字
            comName: 'Left'
        }
    },
    created(){
        // 只要当前的组件被创建
        // 就监听 window 对象的 onhashchange 事件
        window.onhashchange = () => {
            // 箭头函数里面的 this 与外面的this 保持一致
            console.log('监听到了 hash 的变化:' , location.hash)
            if(location.hash === '#/left'){
                this.comName = 'Left'
            }else{
                this.comName = 'Right'
            }
        }
    }
}
</script>

<style lang="less">
.text-box{
    background-color: pink;
    h3 {
        color: blue;
    }
    a{
        margin-left: 20px;
    }
}
.outer{
    background-color: rgb(240, 243, 242);
    padding: 20px;
}

</style> 

Left.vue

<template>
    <div class="left-box">
        <h3 >Left 组件</h3>
    </div>
</template>
<script></script>
<style >
    .left-box{
        background-color: rgb(135, 173, 216);
        min-height: 200px;
    }
</style>

Right.vue

<template>
    <div class="right-box" >
        <h3>Right 组件</h3>
    </div>
</template>

<script></script>

<style lang="less" scoped>
    .right-box{
        background-color: rgb(146, 228, 194);
        min-height: 200px;
    }
</style>

2. vue-router 的基本用法

2.1 什么是 vue-router

vue-router 是 vue.js 官方给出的 路由解决方案 。它只能结合 vue 项目进行使用,能够轻松的管理 SPA 项目中组件的切换。

Vue Router官方

2.2 安装配置以及基本使用

  1. 安装 vue-router 包

    在 vue 2 的项目中,安装 vue-router 的命令如下:

    npm i vue-router@3.5.2 -S
    
  2. 创建路由模块

    src 源代码目录下,新建 router/index.js 路由模块,并初始化如下代码:

    //  1. 导入 Vue VueRouter
    import Vue from 'vue'
    import VueRouter from 'vue-router'
    // 2. 调用 Vue.use() 函数,把VueRouter 安装为 Vue 的插件
    //     在 vue 中安装插件都是使用其 use 方法
    Vue.use(VueRouter)
    // 3. 创建路由实例对象
    const router = new VueRouter()
    // 4. 向外共享路由的实例对象
    export default router
    
  3. 导入并挂载路由模块

    main.js 入口文件中导入并且挂载

    import Vue from 'vue'
    import App from './App.vue'
    // 1.导入路由模块 拿到路由实例对象
    import router from '@/router//index.js'
    
    new Vue({
      render: h => h(App),
      // 2.在 vue 项目中,挂载路由
      router: router
    }).$mount('#app')
    
  4. 声明路由链接和占位符

    App.vue 中声明链接和占位符

    使用 router-link 链接代替普通的 a 链接

    • 标签名不一样
    • to 代替 href
    • hash地址不用加 #
    • 之后浏览器渲染页面会渲染为 a 链接
    <div class="outer">
        <div class="text-box">
            <h1> App.vue 根组件</h1>
            <!--
            <a href="#/left">Left</a> 
            <a href="#/right">Right</a>
    		-->
            <router-link to="/left">Left</router-link>
            <router-link to="/right">Right</router-link>
        </div>
        <hr>
        <!-- 在项目中安装配置了 vue-router,就可以使用 router-view 这个组件 -->
        <!-- 作用:占位符 给组件占位 -->
        <router-view></router-view>
    </div>
    

    在 路由模块 index.js 中添加路由规则

    //  1. 导入 Vue VueRouter
    import Vue from 'vue'
    import VueRouter from 'vue-router'
    // 导入需要的组件
    import Left from '@/components/Left.vue'
    import Right from '@/components/Right.vue'
    // 2. 调用 Vue.use() 函数,把VueRouter 安装为 Vue 的插件
    //     在 vue 中安装插件都是使用其 use 方法
    Vue.use(VueRouter)
    // 3. 创建路由实例对象
    const router = new VueRouter({
      // routes 是一个数组
      // 作用:定义 hash 地址 与 组件 之间的对应关系
      routes:[
        {path: '/left', component: Left},
        {path: '/right', component: Right},
      ]
    })
    // 4. 向外共享路由的实例对象
    export default router
    

注意点:在 模块化导入 的时候,如果给定的是文件夹,则默认导入这个文件夹下的 index.js 的文件

3. vue-router 常见用法

3.1 路由重定向

路由重定向指的是:用户在访问地址A的时候,强制用户跳转到地址C,从而展示特定的组件页面。通过路由规则的 redirect 属性,指定一个新的路由地址,可以很方便地设置路由的重定向。

const router = new VueRouter({
  // routes 是一个数组
  // 作用:定义 hash 地址 与 组件 之间的对应关系
  routes:[
    //  当用户访问的是 / 重定向到 /left
    {path: '/', redirect: '/left'},
    // 路由规则
    {path: '/left', component: Left},
    {path: '/right', component: Right},
  ]
})

3.2 嵌套路由

通过路由实现组件的嵌套显示,叫做嵌套路由。

  1. 在 Right.vue 中声明子级路由链接路由占位符

    <!-- 子级路由链接 -->
    <router-link to="/right/tab1">Tab1</router-link>
    <router-link to="/right/tab2">Tab2</router-link>
    <hr>
    <!-- 子级路由占位符 -->
    <router-view></router-view>
    
  2. src/router/index.js 模块中,导入需要的组件,并使用 children 属性声明子路由规则

    import Tab1 from '@/components/Tab1.vue'
    import Tab2 from '@/components/Tab2.vue'
    
    const router = new VueRouter({
      // routes 是一个数组
      // 作用:定义 hash 地址 与 组件 之间的对应关系
      routes:[
        //  当用户访问的是 / 重定向到 /left
        {path: '/', redirect: '/left'},
        // 路由规则
        {path: '/left', component: Left},
        {
          path: '/right',
          component: Right,
          redirect: '/right/tab1',
          children: [
            // 子路由规则
            {path: 'tab1',  component: Tab1},
            {path: 'tab2',  component: Tab2},
          ]
        },
      ]
    })
    

    3.3 默认子路由

    如果 children 数组中某个路由规则的 path 值为空字符串,则这条路由规则叫做 默认子路由

children: [
    // 默认子路由
    {path: '',  component: Tab1},
    // 子路由规则
    {path: 'tab1',  component: Tab1},
    {path: 'tab2',  component: Tab2},
]

3.3 动态路由匹配

3.3.1 动态路由的概念

动态路由指的是:把 Hash 地址中可变的部分定义为参数项,从而提高路由规则的复用性。在 vue-router 中使用英文的冒号 : 来定义路由的参数项。

{path: '/left/:id', component: Left}

{path: '/left/1', component: Left},
{path: '/left/2', component: Left},
{path: '/left/3', component: Left},   

如何拿到参数项有下面两种: 3.3.2 和 3.3.3

3.3.2 参数对象 参数值

  • this.$route是路由的参数对象
  • 可以在组件中通过 this.$route.params.xxx 访问到路由 path 传递的参数 xxx,其中 this 可以省略,可以写成 $route.params.id
  • this.$routr是路由的导航对象

3.3.3 为路由开启 props 传参

index.js 中为路由规则 props 传参,从而方便的拿到动态参数的值

{path: '/left/:id', component: Left , props: true},

Left.vue 使用props 接收

props: ['id']

3.3.4 拓展 query 和 fullPath

  • 在 hash 地址中,/后面的参数项,叫做 路径参数

    路由参数对象中,需要使用 this.$route.params 来访问路径参数

  • 在 hash 地址中 ,? 后面的参数项,叫做 查询参数

    路由参数对象中,需要使用 this.$route.query 来访问查询参数

  • this.$route.path路径部分,如 /left/2

  • this.$route.fullPath完整的地址,如 /left/2?name=zs&age=30

3.4 编程式导航跳转

3.4.1 声明式导航和编程式导航

  • 在浏览器中,点击链接实现导航的方式,叫做声明式导航

    如:普通网页的 <a> 链接,vue 项目的 <router-link>

  • 在浏览器中,通过 API 方法实现导航的方式,叫做编程式导航

    普通网页中调用location.href跳转到新页面的方式

3.4.1 常用 vue-router 中的编程式导航 API

this.$router导航对象

下面的代码在标签行内书写必须省略 this,否则报错

  • this.$router.push('hash 地址')

    跳转到指定的 hash 地址,并增加一条历史记录

  • this.$router.replace('hash 地址')

    跳转到指定的 hash 地址,并替换掉当前的历史记录

  • this.$router.go(数值 n)

    • 可以在浏览历史中前进和后退
    • 负数代表后退,负数代表前进
  • this.$router.back() 后退一步

  • this.$router.forward() 前进一步

3.5 导航守卫

3.5.1 概念

导航守卫可以控制路由的访问权限。

在这里插入图片描述

3.5.2 全局前置守卫

每次发生路由的 导航跳转 时,都会 触发全局前置守卫 。因此,在全局前置守卫中,程序员可以对每个路由 进行访问权限的控制

  • 调用路由实例对象的 beforeEach 方法,即可声明 " 全局前置守卫 "
  • 每次发生路由导航跳转的时候,都会自动触发 callback 这个回调函数
const router = new VueRouter({...})                
// 全局守卫导航
// 只要发生了路由跳转 必然触发beforeEach中的回调函数
router.beforeEach(callback)                              

3.5.3 回调函数的3个形参

  • to将要访问的路由的信息对象
  • from将要离开的路由对象的信息
  • next 是一个函数 调用 next() 表示放行,允许这次路由导航
const router = new VueRouter({...})    
router.beforeEach((to, from, next) => {
    //code...
})                              

3.5.4 next 函数的 3 种调用方式

在这里插入图片描述

3.5.5 控制访问权限 - 小案例

等于情况下可以访问 /main 到达主页,未登录情况下强制跳转到 /login 登录页面

<router-link to="/main">main 主页</router-link>
router.beforeEach((to, from, next) => {
  //  1.拿到将要访问的 hash 地址
  //  2.判断 hash 地址是不是 /main
  //  3.如果等于  读取 localStorage 中的 token 有则放行,无则跳转 /login
  //  4.如果不等于 直接放行
  if(to.path === '/main'){
    const token = localStorage.getItem('token')
    if(token){
      next()
    } else {
      next('/login')
    }
  } else {
    next()
  }
})
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值