Vue 入门到实战 十

10章****Vue Router​​​​​​​

目录

[10.1 什么是路由](#10.1 什么是路由)

[10.2 Vue Router的安装](#10.2 Vue Router的安装)

[10.2.1 本地独立版本方法](#10.2.1 本地独立版本方法)

[10.2.2 CDN方法](#10.2.2 CDN方法)

[10.2.3 NPM方法](#10.2.3 NPM方法)

[10.2.4 命令行工具(Vue CLI)方法](#10.2.4 命令行工具(Vue CLI)方法)

[10.3 Vue Router的基本用法](#10.3 Vue Router的基本用法)

[10.3.1 跳转与传参](#10.3.1 跳转与传参)

[10.3.2 配置路由](#10.3.2 配置路由)

[10.4 Vue Router高级应用](#10.4 Vue Router高级应用)

[10.4.1 动态路由匹配](#10.4.1 动态路由匹配)

[10.4.2 嵌套路由](#10.4.2 嵌套路由)

[10.4.3 编程式导航](#10.4.3 编程式导航)

[10.4.4 命名路由](#10.4.4 命名路由)

[10.4.5 重定向​编辑](#10.4.5 重定向编辑)

[10.4.6 路由组件props传参](#10.4.6 路由组件props传参)

[10.4.7 HTML5 历史记录模式](#10.4.7 HTML5 历史记录模式)

[10.5 路由钩子函数](#10.5 路由钩子函数)

[10.5.1 全局前置钩子函数](#10.5.1 全局前置钩子函数)

[10.5.2 全局解析钩子函数](#10.5.2 全局解析钩子函数)

[10.5.3 全局后置钩子函数](#10.5.3 全局后置钩子函数)

[10.5.4 某个路由的钩子函数](#10.5.4 某个路由的钩子函数)

[10.5.5 组件内的钩子函数](#10.5.5 组件内的钩子函数)

[10.6 路由元信息](#10.6 路由元信息)


10.1 什么是路由

路由,本是一个网络工程术语,是指分组从源到目的地时,决定端到端路径的网络范围的进程。在Web前端单页面应用中,路由描述的是URL与UI之间的映射关系,这种映射是单向的,即URL变化引起UI更新(无需刷新页面)。

Vue Router 是 Vue.js 官方的路由管理器,它和 Vue.js 的核心深度集成,使构建单页面应用变得更加容易。

10.1.1 SPA与前端路由

SPA指的是一个web网站只有唯一的一个HTML页面,所有组件的展示与切换都在唯一的一个页面内完成。

此时,不同组件之间的切换需要通过前端路由来实现。

结论:在 SPA 项目中,不同功能之间的切换,要依赖于前端路由来完成!

10.1.2 什么是前端路由

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

图是参考这篇文章:vue-router 路由超详细教程_vue router-CSDN博客

10.2 Vue Router的安装

10.2.1 本地独立版本方法

可通过地址"https://unpkg.com/vue-router@next"将最新版本的Vue Router库(vue-router.global.js)下载到本地(在页面上右击,在弹出的快捷菜单中选择另存为),编写本书时,最新版本是4.0.13。然后,在界面文件中引入vue-router.global.js库,示例代码如下。

<script src="js/vue-router.global.js"></script>

10.2.2 CDN方法

在界面文件中可通过CDN(Content Delivery Network,内容分发网络)引入最新版本的Vue Router库,示例代码如下。

<script src="https://unpkg.com/vue-router@next"></script>

对于生产环境,建议使用固定版本,以免因版本不同带来兼容性问题,示例代码如下。

<script src="https://unpkg.com/vue-router@4.0.13/dist/vue-router.global.js"></script>

10.2.3 NPM方法

在使用Vue.js构建大型应用时推荐使用NPM安装最新稳定版的Vue Router,因为NPM能很好地和webpack模块打包器配合使用,示例如下。

npm install vue-router@next

10.2.4 命令行工具(Vue CLI)方法

为提高单页面应用程序的开发效率,我们现在开始使用Vue CLI(Vue 脚手架)搭建Vue.js项目。

Vue CLI是一个基于Vue.js进行快速开发的完整系统,提供如下功能。

l 通过@vue/cli实现交互式项目脚手架;

l 通过@vue/cli + @vue/cli-service-global实现零配置原型开发;

l 一个运行时依赖@vue/cli-service,该依赖可升级,基于webpack构建,并带有合理的默认配置;可通过项目的配置文件进行配置;可通过插件进行扩展;

l 一个丰富的官方插件集合,集成了前端生态工具;

l 提供一套创建和管理Vue.js项目的用户界面。

Vue CLI 致力于将Vue.js生态工具基础标准化。确保各种构建工具平稳衔接,让开发者专注在撰写应用上,而不必纠结配置的问题。

1.全局安装Vue CLI

打开cmd命令行窗口,输入命令npm install -g @vue/cli全局安装Vue脚手架,输入命令vue --version查看版本(测试是否安装成功)。如果需要升级全局的 Vue CLI,在cmd命令行窗口运行npm update -g @vue/cli命令即可。

2.打开图形化界面

安装成功后,在命令行窗口,继续输入命令vue ui打开一个浏览器窗口,并以图形化界面引导至项目创建的流程。

3.创建项目--创建项目界面

4.使用VSCode打开项目

使用VSCode打开(File ---> Open Folder,选择项目目录)第3步创建的项目router-demo。打开后,在Terminal终端输入npm run serve命令启动服务。

5.运行项目

在浏览器地址栏中,访问http://localhost:8080/即可运行项目router-demo。通过http://localhost:8080/访问时,打开的页面是public目录下的index.html。index.html是一个普通的html文件,让它与众不同的是"<div id="app"></div>"这句程序,下面有一行注释,构建的文件将会被自动注入,也就是说我们编写的其他的内容都将在这个div中展示。另外,整个项目只有这一个html文件,所以这是一个单页面应用,当我们打开这个应用,表面上可以看到很多页面,实际上它们都在这一个div中显示。

在main.js中,创建了一个Vue对象。该Vue对象的挂载目标是"#app"(与index.html中的id="app"对应);router代表该对象包含Vue Router,并使用项目中定义的路由(在src/router目录下的index.js文件里定义)。

10.3 Vue Router的基本用法

使用Vue Router动态加载不同组件时,需要将组件(Components)映射到路由(Routers),然后告诉Vue Router在哪里显示它们。

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

10.3.1 路由安装

① 安装 vue-router 包

bash 复制代码
npm install vue-router@4

② 创建路由模块(vue3.0)

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

javascript 复制代码
import { createRouter, createWebHistory } from 'vue-router'
//导入组件
import SecondView from '../views/SecondView.vue'
import ThirdView from '../views/ThirdView.vue'
//定义路由
const routes = [
  {
    path: '/first',
    name: 'first',
    //导入组件
    component: () => import('../views/FirstView.vue')
  },
  {
    path: '/second/:uname/:pwd',
    name: 'second',
    //导入组件
    component: SecondView
  },
  {
    path: '/third/:uname/post/:pwd/post/:age',
    name: 'third',
    //导入组件
    component: ThirdView
  }
] 
//创建路由实例router(管理路由),传入routes配置
const router = createRouter({
    
  history: createWebHistory(import.meta.env.BASE_URL),
  routes
})
export default router

③ 导入并挂载路由模块

在 src/main.js 入口文件中,导入并挂载路由模块。示例代码如下:

javascript 复制代码
import './assets/main.css'
// import Vue from 'vue'
// import App from './App.vue'
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(router)
app.mount('#app')

④ 声明路由链接和占位符

在 src/App.vue 组件中,使用 vue-router 提供的 <router-link><router-view> 声明路由链接和占位符:

javascript 复制代码
<template>
  <nav>
    <router-link to="/first?uname=chenheng&pwd=123456">第一个页面</router-link> |
    <router-link to="/second/chenheng1/654321">第二个页面</router-link>|
    <router-link to="/third/:张三/post/:654321/post/:18">第三个页面</router-link>
  </nav>
 <!--router-view表示路由出口,将匹配到的组件(相当于链接的页面)渲染在这里。 -->
  <router-view/>
</template>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}
nav {
  padding: 30px;
}
nav a {
  font-weight: bold;
  color: #2c3e50;
}
nav a.router-link-exact-active {
  color: #42b983;
}
</style>

10.3.2 跳转与传参

Vue Router有两种跳转,第一种是使用内置的<router-link>组件,默认渲染一个<a>标签,示例代码如下。

<router-link>组件与一般组件一样,to是一个prop,指定跳转的路径。使用<router-link>组件,在HTML5的History模式下将拦截点击,避免浏览器重新加载页面。

Vue Router的第二种跳转方式需要在JavaScript里进行,类似于window.location.href。这种方式需要使用router实例方法push或replace。

javascript 复制代码
Vue Router的第二种跳转方式需要在JavaScript里进行,类似于window.location.href。这种方式需要使用router实例方法push或replace。
<template>
  <div>第一个页面</div>
  <button @click="goto">去第二个页面</button>
</template>
<script>
export default {
  methods: {
    goto () {
      // 也可以使用replace方法,与replace属性一样不会向history添加新记录
      this.$router.push('/MView2')
    }
  }
}

路由传参,一般有两种方式:query和params。不管哪种方式都可以是通过修改URL来实现。

(1)query传参

query传递参数的示例代码如下:

<router-link to="/?id=888&pwd=999">

通过$route.query获取路由中的参数,示例代码如下:

<h4>id:{{$route.query.id}}</h4>

<h4>pwd:{{$route.query.pwd}}</h4>

(2)params传参

在路由规则中定义参数,修改路由规则的path属性(动态匹配),示例代码如下。

{

path: '/:id/:pwd',

name: 'MView1',

component: MView1

}

<router-link to="/888/999">

通过$route.params获取路由中的参数,示例代码如下:

<h4>id:{{$route.params.id}}</h4>

<h4>pwd:{{$route.params.pwd}}</h4>

10.3.3 配置路由

路由配置,通常在前端工程项目的src/router/index.js文件中进行。首先,需要在前端工程项目的src/main.js和src/router/index.js文件中,分别导入vue和vue-router模块,并在main.js中执行use方法注册路由。

10.4 Vue Router高级应用

10.4.1 动态路由匹配

如果有多个参数,即多个冒号,则route.params中保存为对象。例如,路由路径path为/user/:uname/:pwd,则对应的访问路径为/user/zhangsan/123456,route.params中的对象为{ uname: 'zhangsan', pwd: '123456'}。另外,也可以使用post进行多个动态参数传递,例如,路由路径path为/user/:uname/post/:pwd/post/:age,则对应的访问路径为/user/:lisi/post/:654321/post/:18,$route.params中的对象为{ uname: 'lisi', pwd: '123456', age: '18'}。

route路由信息对象表示当前激活的路由状态信息,每次成功导航后都将产生一个新的对象。除了route.params外,$route对象还提供其他许多有用的信息

|---------|-----------------|-----------------------------------------------------------------------------------------------------------|
| 序 号 | 属 性 名 称 | |
| 1 | $route.path | 对应当前路由的路径,如/third/:张三/post/:654321/post/:18 |
| 2 | $route.params | 一个key:value对象,包含了所有动态参数,如果没有参数,则是一个空对象,如{ "uname": ":张三", "pwd": ":654321", "age": ":18" } |
| 3 | route.query | 一个key:value对象,表示URL查询参数。例如,/first?uname=chenheng\&pwd=123456,则有route.query.uname为chenheng。如果没有查询参数,则是空对象 |
| 4 | $route.hash | 当前路由的哈希值(不带#),如果没有哈希值,则为空字符串 |
| 5 | $route.fullPath | 完成解析后的URL,包含查询参数和哈希的完整路径 |
| 6 | $route.matched | 返回数组,包含当前匹配的路径中包含的所有片段所对应的配置 |
| 7 | $route.name | 当前路径名称 |
| 8 | $route.meta | 路由元信息 |

10.4.2 嵌套路由

嵌套路由,即路由的多层嵌套,也称为子路由。在实际应用中,嵌套路由相当于多级菜单,一级菜单下有二级菜单,二级菜单下有三级菜单,等等。

首先,在根组件App.vue中定义基础路由(相当于一级菜单)导航;其次,定义基础路由对应的组件;最后,完成所有嵌套路由组件的定义,并在router/index.js文件中定义嵌套路由。

如果'vue-cli-service' 不是内部或外部命令,也不是可运行的程序

npm install -g@vue/cli

详细代码:

代码目录

main.js

javascript 复制代码
//main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'

createApp(App).use(router).mount('#app')

router/index.js

javascript 复制代码
//router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
import ProductView from '../views/ProductView.vue'

const routes = [
  {
    path: '/',
    name: 'home',
    component: HomeView
  },
  {
    path: '/about',
    name: 'about',
    component: () => import('../views/AboutView.vue')
  },
  {
    path: '/product',
    name: 'product',
    component: ProductView,
    children:[//子路由
      {
        path: '',  //空子路由为基础路由的默认显示
        component: () => import('../views/AlldevView.vue')
      },
      {
        path: 'alldev',  //注意这里没有'/'
        component: () => import('../views/AlldevView.vue')
      },
      {
        path: 'JavaEE',
        component: () => import('../views/JavaEEView.vue')
      },
      {
        path: 'SpringBoot',
        component: () => import('../views/SpringBoot.vue')
      }
    ]
  }
]

const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes
})

export default router

app.vue

javascript 复制代码
//app.vue
<template>
  <h1>嵌套路由</h1>
  <nav>
    <router-link to="/">首页</router-link> |
    <router-link to="/about">关于我们</router-link> |
    <router-link to="/product">产品介绍</router-link>
  </nav>
  <router-view class="my-view"> </router-view>
</template>

<style>
  #app {
    font-family: Avenir, Helvetica, Arial, sans-serif;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-align: center;
    color: #2c3e50;
  }
  nav {
    padding: 30px;
  }
  nav a {
    font-weight: bold;
    color: #2c3e50;
  }
  nav a.router-link-exact-active {
    color: #42b983;
  }
  .my-view {
    width: 500px;
    margin: 0 auto;
    text-indent: 2em;
    text-align: left;
    padding: 5px 10px;
    border: 1px dashed #42b983;
  }
</style>

alldevView.vue

javascript 复制代码
<template>
    <div>
        <img alt="alldev" src="../images/091883-all.jpg" width="200" height="300">
    </div>
</template>

JavaEEView.vue

javascript 复制代码
<template>
    <div>
        <img alt="javaee" src="../images/079720-javaee.jpg" width="200" height="300">
    </div>
</template>

ProductView.vue

javascript 复制代码
<template>
    <div>
        <p>
            <!--定义嵌套路由-->
            <router-link to="/product/alldev">全栈开发</router-link> |
            <router-link to="/product/JavaEE">Java EE整合开发</router-link> |
            <router-link to="/product/SpringBoot">Spring Boot开发</router-link>
        </p>
         <router-view/>
    </div>
</template>
<style scoped>
    p a {
        text-decoration: none;
    }
</style>

SpringBoot.vue

javascript 复制代码
<template>
    <div>
        <img alt="springboot" src="../images/083960-springboot.jpg" width="200" height="300">
    </div>
</template>

10.4.3 编程式导航

除了使用内置的<router-link>组件,渲染一个<a>标签定义导航链接外,还可以通过编程调用路由(router或this.$router)的实例方法实现导航链接。

前一步

javascript 复制代码
   go1(){
      this.$router.forward()
    },

后退一步

javascript 复制代码
    back1(){
      this.$router.back()
    },

回首页

javascript 复制代码
    goHome(){
      this.$router.push('/') //字符串路由path
    },

看产品介绍

javascript 复制代码
    goProduct(){
      this.$router.push({ //对象
        path: '/product'
      })
    },

代替关于我们

javascript 复制代码
    repAbout(){
      this.$router.replace({
       name: 'home', //命名路由
       params:{uname:'123', pwd:'abc'} //传参
      })
    }

|-------------|-------------|-----------------------------------|----------------------------------------------------------------------------|
| | 方 法 名 称 | 功 能 说 明 | |
| 1 | push() | 跳转到由参数指定的新路由地址,在历史记录中添加一条新记录 | |
| 2 | replace() | 跳转到由参数指定的新路由地址,替换当前的历史记录 | |
| 3 | go(n) | n为整数,在历史记录中向前或后退n步 | |
| 4 | forward() | 在历史记录中向前一步,相当于this.router.go(1) | ![](https://i-blog.csdnimg.cn/direct/d446c7c596a54d3a9373dacd7a0ddec4.png) | | **5** | back() | 在历史记录中后退一步,相当于this.router.go(-1) | |

push()方法和replace()方法的用法相似,唯一不同的是push()方法在历史记录中添加一条新记录,replace()方法不会添加新记录,而是替换当前记录。点击返回,会跳转到上上一个页面。

上面这个小视频的看产品介绍是push模式,看产品介绍1是replace模式,我们点返回的时候,看出来两个返回是不一样的,一个是上一步,一个调回到百度首页。

push()方法和replace()方法的参数可以是字符串、对象、命名路由、带查询参数等多种形式,示例如下。

//字符串路由path

this.$router.push('/')

//对象

this.$router.push({path: '/product'})

//命名路由及params传参,params更像post,是隐性传参

this.$router.push({name: 'home', params:{uname:'123', pwd:'abc'} })

//带查询参数,/product?uname=123&pwd=abc,更像get传参,是显性传参

this.$router.push({path: '/product', query:{uname:'123', pwd:'abc'} })

this.$router.push({name: 'home', state:{uname:'123', pwd:'abc'} })

在home对应的页面可以使用history.state接收数据。

10.4.4 命名路由

{

path: '/',

name: 'home',

component: HomeView

}

<router-link :to="{name: 'home', params: {uname: '123', pwd: 'abc'}}">首页</router-link>

与编程式导航this.$router.push({name: 'home', params:{uname:'123', pwd:'abc'} })功能相同。

10.4.5 重定向

10.4.6 路由组件props传参

10.4.7 HTML5 历史记录模式

| 对比 | hash 模式 | history 模式 |
| url 显示 | url 中带"#" | url 中不带"#" |
| 回车刷新(浏览器刷新按钮) | 页面正常显示 | 后端未配置则页面显示404 |

支持版本 支持低版本浏览器和 IE 浏览器 HTML5 新推出的 API

代码对比

10.5 路由钩子函数

10.5.1 全局前置钩子函数

在Vue Router中,使用router.beforeEach注册一个全局前置钩子函数(在路由跳转前执行),注册示例代码如下。

router.beforeEach(async (to, from) => {

//在ES7标准中新增了async和await关键字,作为处理异步请求的一种解决方案

if (

// 检查用户是否已登录

!isAuthenticated &&

// 避免无限重定向

to.name !== 'Login'

) {

// 将用户重定向到登录页面

return { name: 'Login' }

}

})

10.5.2 全局解析钩子函数

在Vue Router中,使用router.beforeResolve注册一个全局解析钩子函数。与router.beforeEach 类似,在每次导航时都会触发,但是确保在导航被确认之前,同时在所有组件内钩子函数和异步路由组件被解析之后,解析钩子函数就被正确调用。

router.beforeResolve(async to => {

if (to.meta.requiresCamera) {

try {

await askForCameraPermission()

} catch (error) {

if (error instanceof NotAllowedError) {

// ... 处理错误,然后取消导航

return false

} else {

//意料之外的错误,取消导航并把错误传给全局处理器

throw error

}

}

}

})

10.5.3 全局后置钩子函数

在Vue Router中,也可以使用router.afterEach注册全局后置钩子函数,该钩子函数不接收next参数,也不会改变导航本身,在跳转之后判断。对于分析、更改页面标题、声明页面等辅助功能都很有用。示例代码如下。

router.afterEach((to, from) => {

// ...

})

10.5.4 某个路由的钩子函数

10.5.5 组件内的钩子函数

const UserDetails = {

template: `...`,

beforeRouteEnter(to, from) {

// 在渲染该组件的对应路由被验证前调用,不能获取组件实例 `this` !因为当该钩子函数执行时,组件实例还没被创建!

},

beforeRouteUpdate(to, from) {

// 在当前路由改变,但是该组件被复用时调用。举例来说,对于一个带有动态参数的路径`/users/:id`,在`/users/1`和 `/users/2`之间跳转的时候,由于渲染同样的`UserDetails` 组件,因此组件实例会被复用,此钩子函数在此情况下也被调用。因为在这种情况发生的时候,组件已经挂载好了,该钩子函数可以访问组件实例 `this`

},

beforeRouteLeave(to, from) {

// 在导航离开渲染该组件的对应路由时调用与 `beforeRouteUpdate` 一样,它可以访问组件实例 `this`

},

}

10.6 路由元信息

有时,可能希望将任意信息附加到路由上,如过渡名称、访问路由权限等。这些工作可以通过接收属性对象的meta属性来实现,并且它可以在路由地址和导航守卫(路由钩子函数)中都能被访问到。

下面我们用一个完整的例子把路由守卫说明白,首先了解路由守卫是干什么的,就如下这个例子,我开始点击home的页签,系统提示我没有登录,然后页面切入到登录的页面,这是一个很常见的拦截器的功能,就是判断是否有登录,在vue我们就用路由守卫干这件事,所以路由守卫其实简单理解就是拦截器。这个最重要的就是router.beforeEach,代码是写在main.JS中

相关推荐
anyup_前端梦工厂2 小时前
了解几个 HTML 标签属性,实现优化页面加载性能
前端·html
前端御书房2 小时前
前端PDF转图片技术调研实战指南:从踩坑到高可用方案的深度解析
前端·javascript
2301_789169542 小时前
angular中使用animation.css实现翻转展示卡片正反两面效果
前端·css·angular.js
风口上的猪20153 小时前
thingboard告警信息格式美化
java·服务器·前端
程序员黄同学4 小时前
请谈谈 Vue 中的响应式原理,如何实现?
前端·javascript·vue.js
爱编程的小庄4 小时前
web网络安全:SQL 注入攻击
前端·sql·web安全
宁波阿成5 小时前
vue3里组件的v-model:value与v-model的区别
前端·javascript·vue.js
柯腾啊5 小时前
VSCode 中使用 Snippets 设置常用代码块
开发语言·前端·javascript·ide·vscode·编辑器·代码片段
Jay丶萧邦5 小时前
el-select:有关多选,options选项值不包含绑定值的回显问题
javascript·vue.js·elementui
weixin_535854225 小时前
oppo,汤臣倍健,康冠科技,高途教育25届春招内推
c语言·前端·嵌入式硬件·硬件工程·求职招聘