目录
axios?
基本语法
GET 请求
POST 请求?
存在的问题
将 axios 挂载到 Vue 原型
路由
前端路由的概念与原理
SPA(单页面应用程序)与 前端路由
前端路由
前端路由的工作方式
vue-router 的基本使用
安装与配置
安装 vue-router 包
创建路由模块
导入并挂载路由模块
声明路由链接和占位符
注意点
使用 router-link 代替 a 链接
redirect 重定向
嵌套路由
默认子路由
动态路由匹配
为路由规则开启 props 传参
拓展 query 和 fullPath
vue-router 的常见用法
声明式导航&编程式导航
vue-router 中的编程式导航 API
push
replace
go
go 的简化用法
导航守卫
全局前置守卫
守卫方法的 3 个形参
next 函数的三种调用方式?
控制访问权限
axios?
基本语法
GET 请求
<template>
<div class="left-container">
<button @click="getInfo">发起 GET 请求</button>
</div>
</template>
<script>
import axios from 'axios'
export default {
methods: {
async getInfo() {
const {
data: res
} = await axios.get('http://www.liulongbin.top:3006/api/get');
console.log(res);
}
},
}
</script>
POST 请求?
<template>
<div class="right-container">
<button @click="postInfo">发起 POST 请求</button>
</div>
</template>
<script>
import axios from 'axios'
export default {
methods: {
async postInfo() {
const {
data: res
} = await axios.post('http://www.liulongbin.top:3006/api/post', {
name: 'zs',
age: 20
});
console.log(res);
}
},
}
</script>
存在的问题
每个组件进行 axios 访问时,都需要重复写入上述代码,代码的重复率大大提高,复用率降低
将 axios 挂载到 Vue 原型
将 axios 挂载到 vue 原型上,并配置请求根目录
// main.js
// 全局配置 axios 的请求根路径
axios.defaults.baseURL = "http://www.liulongbin.top:3006"
// 将 axios 挂载到 Vue.prototype 上,供每个 vue 组件的实例直接使用
Vue.prototype.$http = axios
// 之后在每个 .vue 组件中发起请求,直接调用 this.$http.get/post 即可
// 不需要再导入 axios
<script>
// 不需要再导入 axios
// import axios from 'axios'
export default {
methods: {
async getInfo() {
const {
data: res
} = await this.$http.get('/api/get');
console.log(res);
}
},
}
</script>
<script>
export default {
methods: {
async postInfo() {
const {
data: res
} = await this.$http.post('/api/post', {
name: 'zs',
age: 20
});
console.log(res);
}
},
}
</script>
优点:不需要在每个组件中都导入 axios,可以直接使用 this.$http.get/post() 进行调用
缺点:无法实现 api 接口复用,需要在每一个需要发起请求的 vue 组件中使用 get/post 发起请求
路由
前端路由的概念与原理
路由:router,即对应关系
SPA(单页面应用程序)与 前端路由
SPA 指的是一个 web 网站只有唯一的一个 HTML 页面,所有组件的展示与切换都在这唯一的一个页面内完成
此时,不同组件之间的切换需要通过前端路由来实现
在 SPA 项目中,不同功能之间的切换,都要依赖于前端路由来完成
前端路由
概念:Hash 地址与组件之间的对应关系
# 可以理解为锚链接,锚链接与 Hash 地址含义相同
锚链接的特性:不会导致页面的刷新,但会导致页面的上下跳转,会导致历史纪录的变化
前端路由的工作方式
- 用户点击页面上的路由链接
- 导致 URL 地址栏中的 Hash 值发生改变
- 前端路由监听到了 Hash 地址的变化
- 前端路由将当前 Hash 地址对应的组件渲染到浏览器中
path 和 component 的对应关系
<template>
<div class="app-container">
<a href="#/Home">首页</a>
<a href="#/Movie">电影</a>
<a href="#/About">关于</a>
<component :is="comName"></component>
</div>
</template>
<script>
// 导入组件
import Home from '@/components/Home.vue'
import Movie from '@/components/Movie.vue'
import About from '@/components/About.vue'
export default {
data() {
return {
// 在动态组件的位置需要展示的组件的名称,值必须是字符串类型
comName: 'Home',
}
},
created() {
// 只要当前的 App 组件被创建,就立即监听 window 对象的 onhashchange 事件
window.onhashchange = () => {
console.log('监听到了hash地址的变化', location.hash);
switch (location.hash) {
case '#Home':
this.comName = 'Home'
break;
case '#/Movie':
this.comName = 'Movie'
break;
case '#/About':
this.comName = 'About'
break;
default:
break;
}
}
},
// 注册组件
components: {
Home,
Movie,
About
}
}
</script>
vue-router 的基本使用
vue-router 是 vue.js 官方给出的路由解决方案
只能结合 vue 项目进行使用,能够轻松的管理 SPA 项目中的组件切换
vue-router 的官方文档地址:http://router.vuejs.org/zh/?
安装与配置
- 安装 vue-router 包
- 创建路由模块
- 导入并挂载路由模块
- 声明路由链接和占位符
安装 vue-router 包
npm i vue-router@3.5.2 -S
创建路由模块
在 src 源代码目录下,新建 router/index.js 路由模块,并初始化如下代码:
// 导入 Vue 和 VueRouter 的包
import Vue from 'vue'
import VueRouter from 'vue-router'
// 调用 Vue.use() 函数,把 VueRouter 安装为 Vue 的插件
Vue.use(VueRouter)
// 创建路由的实例对象
const router = new VueRouter()
// 向外共享路由的实例对象
export default router
导入并挂载路由模块
// main.js
// 导入路由模块,拿到路由的实例对象
import router from '@/router/index.js'
new Vue({
render: h => h(App),
// 在 Vue 项目中,要想使用路由,必须将实例对象通过下面的方式进行挂载
// route: 路由的实例对象
// router: router 当属性名和属性值同名时,可以简写
router
}).$mount('#app')
声明路由链接和占位符
链接和占位符
<!-- App2.vue -->
<template>
<div class="app-container">
<h1>App2 组件</h1>
<a href="#/Home">首页</a>
<a href="#/Movie">电影</a>
<a href="#/About">关于</a>
<hr />
<!-- 只要在 vue 中配置了 vue-router,就可以使用 router-view 组件 -->
<!-- router-view 的作用:占位符 -->
<router-view></router-view>
</div>
</template>
在路由模块 index.js 中声明路由的对应关系
// 导入 Vue 和 VueRouter 的包
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '@/components/Home.vue'
import Movie from '@/components/Movie.vue'
import About from '@/components/About.vue'
// 调用 Vue.use() 函数,把 VueRouter 安装为 Vue 的插件
Vue.use(VueRouter)
// 创建路由的实例对象
const router = new VueRouter({
// routes 定义一个数组,作用:定义 hash 地址和组件之间的对应关系
routes: [{
// path: '/Home', component: 要展示的组件
path: '/home',
component: Home
},
{ path: '/movie', component: Movie },
{ path: '/about', component: About }
],
})
// 向外共享路由的实例对象
export default router
注意点
- 在导入组件时,如果想用 App2.vue 替换掉 App.vue,则可以直接将 import App from './App.vue' 替换为 import App from './App2.vue',其他的都不要更改
- 在进行模块化导入时,如果给定的是一个文件夹,则默认导入该文件夹下名为 index.js 的文件
import Vue from 'vue'
// 在导入组件时,如果想用 App2.vue 替换掉 App.vue,则可以直接将 import App from './App.vue' 替换为?import App from './App2.vue',其他的都不要更改
// import App from './App.vue'
import App from './App2.vue'
// 导入路由模块,拿到路由的实例对象
// 在进行模块化导入时,如果给定的是一个文件夹,则默认导入该文件夹下名为 index.js 的文件
// import router from '@/router/index.js'
import router from '@/router'
使用 router-link 代替 a 链接
- router-link 与 a 标签作用相同
- to 属性相当于 href,其值不需要再添加 #,访问链接时会自动添加
<template>
<div class="app-container">
<!-- 当安装和配置了 vue-router 之后,就可以使用 router-link 替代普通的 a 链接了 -->
<router-link to="/home">首页</router-link>
<router-link to="/movie">电影</router-link>
<router-link to="/about">关于</router-link>
<!-- <a href="#/home">首页</a> -->
<!-- <a href="#/movie">电影</a> -->
<!-- <a href="#/about">关于</a> -->
</div>
</template>
redirect 重定向
路由重定向:用户在访问地址 A 的时候,强制用户跳转到地址 C,从而展示特定的组件页面
通过路由规则的 redirect 属性,指定一个新的路由地址,可以很方便地设置路由的重定向
<!-- index.js -->
const router = new VueRouter({
routes: [
// 当用户访问 / 的时候,通过 redirect 属性跳转到 /home 对应的路由规则
{ path: '/', redirect: '/home' },
{ path: '/home', component: Home },
{ path: '/movie', component: Movie },
{ path: '/about', component: About }
],
})
嵌套路由
通过路由实现组件的嵌套展示,称为嵌套路由
- 通过 router-link 设置路由链接
- 通过 router-view 设置子级路由占位符
- 在 router/index.js 中设置路由的对应关系
<!-- 组件 Tab1 和 Tab2 的父组件 About 组件 -->
<template>
<div class="about-container">
<h3>About 组件</h3>
<!-- 子级路由链接 -->
<router-link to="/about/tab1">tab1</router-link>
<router-link to="/about/tab2">tab2</router-link>
<hr>
<!-- 子级路由占位符 -->
<router-view></router-view>
</div>
</template>
- 在父级路由规则中,通过 children 属性,嵌套声明子级路由规则
- 子级路由规则中,path 属性值不需要添加 " /?"
import Tab1 from '@/components/tabs/Tab1.vue'
import Tab2 from '@/components/tabs/Tab2.vue'
const router = new VueRouter({
routes: [
{ // about 页面的路由规则(父级路由规则)
path: '/about',
component: About,
// 通过 redirect 重定向路由
redirect: '/about/tab1',
// 通过 children 属性,嵌套声明子级路由规则
children: [
// 子路由规则中不要添加斜线
{ path: 'tab1', component: Tab1 }, // 访问 /about/tab1 时,展示 Tab1 组件
{ path: 'tab2', component: Tab2 } // 访问 /about/tab2 时,展示 Tab2 组件
],
}
],
})
默认子路由
- 父级路由中的 router-link 标签的 to 属性值,必须与 index 中对应的路由规则中的 path 值相同
<template>
<div class="about-container">
<!-- 默认子路由链接 -->
<router-link to="/about">tab1</router-link>
</div>
</template>
const router = new VueRouter({
routes: [
{
path: '/about',
component: About,
// redirect: '/about/tab1',
children: [
// 默认子路由,如果 children 数组中,某个路由规则的 path 值为空字符串,则这条路由规则,称为 "默认子路由"
{ path: '', component: Tab1 }, // 访问 /about/tab1 时,展示 Tab1 组件
{ path: 'tab2', component: Tab2 } // 访问 /about/tab2 时,展示 Tab2 组件
],
}
],
})
动态路由匹配
把 Hash 地址中的可变部分定义为参数项,从而提高路由规则的复用性
在 vue-router 中使用英文的冒号 (:) 来定义路由的参数项
- 在 App2.vue 中通过 router-link 设置路由链接
- 在 router/index.js 中定义路由的参数项
- 在 Movie.vue 中通过?this.$route.params.id?获取相应参数项的?id?值
<!-- 在 App2.vue 中通过 router-link 设置路由链接 -->
<template>
<div class="app-container">
<router-link to="/movie/1">海绵宝宝</router-link>
<router-link to="/movie/2">蟹老板</router-link>
<router-link to="/movie/3">派大星</router-link>
</div>
</template>
// 在 router/index.js 中定义路由的参数项
const router = new VueRouter({
routes: [
// 当使用 : 定义了路由的参数项后,相应组件的 this 值中便会生成相应的 id 属性
// 需求:在 Movie 组件中,根据 id 的值,展示对应电影的详情信息
{ path: '/movie/:id', component: Movie, },
],
})
<!-- 在 Movie.vue 中通过?this.$route.params.id?获取相应参数项的?id?值 -->
<template>
<div class="movie-container">
<!-- this.$route 是路由的参数对象 -->
<!-- 通过 this.$route.params.id 获取相应选项的 id 值 -->
<!-- this 可以省略 -->
<h3>Movie 组件 --- {{ $route.params.id }}</h3>
</div>
</template>
- this.$route 是路由的参数对象
- this.$router 是路由的导航对象?
为路由规则开启 props 传参
- 在 Movie.vue 中定义 props 数组,接收 props 数据:props[ 'id' ]
- 在 index.js 的路由规则中添加 props: true 为当前这条路由规则开启 props 传参
- 在 Movie.vue 中就可以直接使用动态路由参数项 id 获取相应参数项的 id 值
<template>
<div class="movie-container">
<!-- 3.在 Movie.vue 中就可以直接使用动态路由参数项 id 获取相应参数项的 id 值 -->
<h3>Movie 组件 --- {{id}}</h3>
</div>
</template>
<script>
export default {
// 1.在 Movie.vue 中定义 props 数组,接收 props 数据:props[ 'id' ]
// 接收 props 数据
props: ['id'],
}
</script>
当路由规则的 path 中含有动态参数项时,可以通过 props:true 为当前这条路由规则开启 props 传参;否则没有意义
const router = new VueRouter({
routes: [
// 2.在 index.js 的路由规则中添加 props: true 为当前这条路由规则开启 props 传参
{ path: '/movie/:id', component: Movie, props: true },
],
})
拓展 query 和 fullPath
注意1:
- 在 hash 地址中,斜线 "/" 之后的参数项是 "路径参数"
- 在路由参数对象中,需要使用 this.$route.params 来访问路径参数
注意2:
- 在 hash 地址中,问号 "?" 后面的参数称为 "查询参数"
- 在路由参数对象中,需要使用 this.$route.query 来访问查询参数
<template>
<div class="app-container">
<router-link to="/movie/2?name=zs">蟹老板</router-link>
</div>
</template>
注意3:
- fullPath:既包含路径参数又包含查询参数
- path:只包含路径参数
- 之后的开发中,如果要使用完整路径,使用 fullPath
- 只需要路径,不需要查询参数,使用 path
vue-router 的常见用法
声明式导航&编程式导航
在浏览器中,点击链接实现导航的方式,叫做声明式导航
- 普通网页中的 <a> 链接、vue 项目中的 <router-link> 都属于声明式导航
在浏览器中,调用 API 方法实现导航的方式,叫做编程式导航
- 普通网页中调用 location.href 跳转到新页面的方式,属于编程式导航
vue-router 中的编程式导航 API
vue-router 提供了许多编程式导航的 API,其中最常用的导航 API 分别是:
- this.$router.push( 'hash 地址' )
- this.$router.replace( 'hash 地址' )
- this.$router.go( '数值 n' )
push
- 跳转到指定的 hash 地址,并增加一条历史记录
- 添加一条历史记录的表现:可以通过浏览器的??前进或者后退页面
<template>
<div class="home-container">
<button @click="gotoHM">跳转到海绵宝宝</button>
</div>
</template>
<script>
export default {
methods: {
gotoHM() {
// 通过编程式导航跳转到指定页面
this.$router.push('/movie/1');
}
},
}
</script>
replace
- 跳转到指定的 hash 地址,并替换掉当前的历史记录
- 替换掉当前历史记录的表现:不可以通过浏览器导航栏中的??前进或者后退页面?
<template>
<div class="home-container">
<button @click="gotoPDX">跳转到派大星</button>
</div>
</template>
<script>
export default {
methods: {
gotoPDX() {
// 通过编程式导航跳转到指定页面,并替换掉当前历史记录
this.$router.replace('/movie/3');
}
},
}
</script>
go
- go(数值 n) 中,n 可以是正数,也可以是负数
- 调用 this.router.go() 方法,可以在浏览历史中前进和后退
<template>
<div class="movie-container">
<button @click="goBack">后退</button>
<button @click="goUp">前进</button>
</div>
</template>
<script>
export default {
methods: {
goBack() {
// 括号中的参数为整数
// 如果后退的层数超过上限,则不进行后退操作
this.$router.go(-1);
},
goUp() {
this.$router.go(1);
}
},
}
</script>
go 的简化用法
在实际开发中,一般只会前进和后退一层页面。因此 vue-router 提供了如下两个便捷方法
- $router.back()
- 在历史记录中,后退到上一个页面
- $router.forward()
- 在历史记录中,前进到下一个页面
<template>
<div class="movie-container">
<!-- 方法中只有一行代码,使用行内样式 -->
<!-- 注意:this 必须去掉 -->
<button @click="$router.back()">后退</button>
<button @click="$router.forward()">前进</button>
</div>
</template>
导航守卫
导航守卫可以控制路由的访问权限
全局前置守卫
每次发生路由的导航跳转时,都会触发全局前置守卫
因此,在全局前置守卫中,程序员可以对每个路由进行访问权限的控制
全局前置守卫的使用步骤:
- 创建路由实例对象
- 调用路由实例对象的 beforeEach 方法,即可声明 "全局前置守卫"
- 每次发生路由导航跳转时,都会自动触发 beforeEach(fn) 中的 fn 回调函数
// 1.创建路由的实例对象
const router = new VueRouter({});
// 2.调用路由实例对象的 beforeEach 方法,即可声明 "全局前置守卫"
// 3.每次发生路由导航跳转时,都会自动触发 beforeEach(fn) 中的 fn 回调函数
router.beforeEach((to, from, next) => {
// to 是将要访问的路由的信息对象
// from 是将要离开的路由的信息对象
// next 是一个函数,调用 next() 表示放行,允许这次路由导航
next(); // 无论跳转到哪个页面都放行
});
守卫方法的 3 个形参
- to 是将要访问的路由的信息对象
- from 是将要离开的路由的信息对象
- next 是一个函数,调用 next() 表示放行,允许这次路由导航
next 函数的三种调用方式
- 如果当前用户拥有后台主页的访问权限,直接放行:next()
- 如果当前用户没有后台主页的访问权限,强制其跳转到登录页面:next('/login')
- 如果当前用户没有后台主页的访问权限,不允许跳转到后台主页:next(false)
控制访问权限
router.beforeEach((to, from, next) => {
// 分析
// 1.要拿到用户将要访问的 hash 地址
// 判断 hash 地址是否等于 /main
// 2.如果等于 /main,则需要登录才能访问成功
// 如果不等于 /main,直接放行
// 3.如果访问的是 /main,需要读取 localStorage 中的 token 值
// 如果 token 有值,直接放行;如果没有 token,强制跳转到登录页面
if (to.path === '/main') {
const token = localStorage.getItem('token');
if (token) {
next(); // 访问的是 /main,且有 token 值
} else {
next('/login'); // 访问的是 /main,没有 token 值
}
} else {
next(); // 访问的不是后台页面,直接放行
}
});
|