路由(vue-router)
目标:
能够在项目中安装和配置路由:createRouter
、app.use(router)
能够使用路由实现单页面应用程序的开发
能够使用嵌套路由:通过children
属性进行路由嵌套
能够实现动态路由匹配:使用冒号声明参数项、this.$route.params
、props: true
能够使用编程式导航:this.$router.push
、this.$router.go
能够使用导航守卫控制路由的访问权限:路由实例.beforeEach((to, from, next) => { /* 必须调 next 函数*/ })
axios的使用
首先安装axios包
npm i axios
,结果报错ERR! ERESOLVE could not resolve ERESOLVE could not resolve
解决办法是在后面加--legacy-peer-deps
即可npm install axios -save --legacy-peer-deps
报错的原因是由于npm不同版本库之间命令不兼容。在left组件发送get请求:
1
2
3
4
5
6
7
8
9
10
11<button @click="getInfo">发起Get请求</button>
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)
}
}
}在right组件发送post请求
1
2
3
4
5
6
7
8
9
10
11<button @click="postInfo">发起 Post 请求</button>
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: 25 })
console.log(res)
}
}
}
考虑问题 – 优化
问题
- 每个组件中,都可能会有发请求的需求,都需要先导入axios,然后调用这些方法,每次用都很麻烦
- 每次请求地址都需要写完整地址,但是我们的请求根路径都完全一样。如果将来后端把根路径改了,我们就需要修改每一个组件,不利于后期维护。
思考
每一个.vue组件都相当于一个vue实例,我们可以理解为:每一个.vue组件都是new Vue()这个构造函数得到的优化1 – 在Vue的原型链上挂载一个axios
1
2
3
4
5// main.js
import axios from 'axios'
// 一般我们不叫axios,而是$http
// 因为vue内置的一些成员都是以$开头的(模仿内置成员)
Vue.prototype.$http = axios这样我们在每一个组件中,就不需要再导入axios,直接通过this/原型访问
优化2 – 全局配置 axios 的请求根路径
在往原型上挂之前,通过axios做一下局域的配置:axios.defaults.baseURL = '请求根路径' // axios自带的属性
组件使用:1
2
3
4async getInfo() {
const { data: res } = await this.$http.get('/api/get')
console.log(res)
}缺点
无法实现api接口的复用:如果这个api在多个页面都需要被用到,每一次都需要重新调这个api接口
axios最优使用 – 实现api接口的复用
使用axios的最优解 —— 封装!(也就是模块化)
将axios接口作为可导入的工具包进行封装
推荐:将其放在utils文件夹下(工具类的意思)
1 | // utils/request.js |
需要几个服务器的接口,就封装几个,用哪个就导入哪个。如:request1封装TB的接口,2封装JD的接口
进一步的封装/模块化
如果有多个组件,都要调用request的articles接口,那么每个组件都要这么写:
1 | import request from '@/utils/request' |
await后面返回的是一个Promise类型的值,所以我们可以把这一块单独拿出去
可以将其进一步的封装
所有的API调用都可以放进 API 文件夹
封装的API文件都以API的命名结尾,可以一眼看出这是个API
1 | // API/articleAPI.js |
然后每个组件都可以这样调用接口
1 | import { getArticleListAPI } from '@/api/articleAPI' |
这样才达到了axios真正的用法
路由的基本配置与使用
什么是路由
路由(router) 就是 对应关系SPA(单页面应用程序) 与 前端路由
SPA指的是一个web网站只有唯一的一个HTML页面,所有组件的展示与切换都在这唯一的一个页面内完成。此时,不同组件之间的切换需要通过前端路由来实现。什么是前端路由
通俗易懂的概念:Hash地址(就是#锚链接) 与 组件 之间的 对应关系
不同的哈希,会展示出不同的组件页面前端路由的工作方式
- 用户点击了页面上的路由链接
- 导致了URL地址栏中的Hash值发生了变化
- 前端路由监听了到Hash地址的变化
- 前端路由把当前Hash地址对应的组件渲染都浏览器中
结论:前端路由,指的是 Hash地址 与 组件之间 的 对应关系
vue-router的基本使用
前端路由的底层原理是监听了浏览器的onhashchange事件,自己去封装前端路由是非常麻烦的一件事,我们可以用现成的包去实现前端路由的处理 – vue-router(vue项目中的一个路由的包,只能在vue项目中用)
什么是vue-router
vue-router是vue.js官方给出的路由解决方案。它只能结合vue项目进行使用,能够轻松的管理SPA项目中组件的切换。
vue-router 的官方文档地址: https://router.vuejs.org/zh/vue-router 安装和配置的步骤
安装vue-router包:
npm i vue-router@3.5.2 -S
如果因为ESLint安装报错,可以加上后缀:npm i vue-router@3.5.2 -S --legacy-peer-deps
vue-router最新版本Vue Router 4 是为 Vue 3 设计的,不兼容Vue2。
所以想在 Vue 2 中使用 Vue Router,安装包的时候需要指定 Vue Router 3 的版本创建路由模块
在src源代码目录下,新建router/index.js路由模块,并初始化如下代码:1
2
3
4
5
6
7
8
9
10
11
12
13// src/router/index.js 就是当前项目的路由模块
// 1. 导入 Vue 和 VueRouter 的包
import Vue from 'vue'
import VueRouter from 'vue-router'
// 2. 调用 Vue.use() 函数,把 VueRouter 安装为 Vue 的插件
Vue.use(VueRouter)
// 3. 创建路由的实例对象
const router = new VueRouter()
// 4. 向外共享路由的实例对象
export default router导入并挂载路由模块
1
2
3
4
5
6
7
8
9// 导入路由模块,目的:拿到路由的实例对象
import router from '@/router/index.js'
new Vue({
render: (h) => h(App),
// 在 Vue 项目中,要想把路由用起来,必须把路由实例对象,通过下面的方式进行挂载
// router:路由的实例对象
router // 这里是简写
}).$mount('#app')导入路由的时候,index.js可以省略 –
import router from '@/router'
在模块化导入的时候,如果只给了一层路径,默认会导入和加载路径下面名字叫index.js的文件声明路由链接和占位符/声明路由的对应关系(路由规则)
声明占位符:
App.vue甚至不需要导入组件,只需要声明一个占位符即可,通过a链接切换对应的组件1
2
3
4
5<a href="#/left">left </a>
<a href="#/right"> right</a>
<!-- 只要在项目中安装和配置了 vue-router,则就可以使用 router-view 这个组件 -->
<!-- 作用:占位符 -->
<router-view></router-view>在路由模块声明路由的对应关系 – 路由规则:
1
2
3
4
5
6
7
8
9
10
11
12
13// 导入需要的组件
import Left from '@/components/Left-item.vue'
import Right from '@/components/Right-item.vue'
// 3. 创建路由的实例对象
const router = new VueRouter({
// routes 是一个数组,作用:定义 “hash 地址” 与 “组件”之间的对应关系
routes: [
// 路由规则
{ path: '/left', component: Left },
{ path: '/right', component: Right }
]
})使用router-link代替a链接
router-link本质上也会被渲染成a链接1
2
3
4<!-- 当安装和配置了 vue-router 后,就可以使用 router-link来替代普通的a链接 -->
<!-- 优势:不用写前面的#,它会在点这个router-link的时候自动在前面加上# -->
<router-link to="/left">left</router-link>
<router-link to="/right">right</router-link>
路由重定向 – redirect
路由重定向指的是:用户在访问地址A的时候,强制用户跳转到地址C,从而展示特定的组件页面。通过路由规则的redirect属性,指定一个新的路由地址,可以很方便地设置路由的重定向:
1 | const router = new VueRouter({ |
嵌套路由
通过路由实现组件的嵌套展示,叫做嵌套路由。
如果某个组件本身就是通过路由的方式呈现出来的,在这个组件里又放一些路由规则,这样就形成了路由嵌套。
声明子级路由标签和占位符
1
2
3
4
5
6
7// Right.vue
<!-- 子级路由链接 -->
<router-link to="/right/tab1">tab1</router-link>
<router-link to="/right/tab2">tab2</router-link>
<hr>
<!-- 子级路由占位符 -->
<router-view></router-view>声明嵌套路由的规则 – 路由对应关系
通过Children属性声明子路由规则
在src/router/index.js路由模块中,导入需要的组件,并通过children属性声明子路由规则:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21import Tab1 from '@/components/tab1.vue'
import Tab2 from '@/components/tab2.vue'
// 3. 创建路由的实例对象
const router = new VueRouter({
// routes 是一个数组,作用:定义 “hash 地址” 与 “组件”之间的对应关系
routes: [
// 当用户访问 / 的时候,通过 redirect 属性跳转到 /left 对应的路由规则
{ path: '/', redirect: '/left' },
{ path: '/left', component: Left },
{ // right页面的路由规则(父级路由规则)
path: '/right',
component: Right,
children: [ // 通过children属性,嵌套声明子级路由规则
{ path:''}
{ path: 'tab1', component: Tab1 },
{ path: 'tab2', component: Tab2 }
]
}
]
})注意:子路由规则,不要以斜线开头!
嵌套路由的路由重定向
在right的路由规则中加上redirect即可,这样路径/right就直接跳转到了/right/tab21
2
3
4
5
6
7
8
9
10
11
12
13
14routes: [
// 当用户访问 / 的时候,通过 redirect 属性跳转到 /left 对应的路由规则
{ path: '/', redirect: '/left' },
{ path: '/left', component: Left },
{ // right页面的路由规则(父级路由规则)
path: '/right',
component: Right,
redirect: '/right/tab2',
children: [ // 通过children属性,嵌套声明子级路由规则
{ path: 'tab1', component: Tab1 },
{ path: 'tab2', component: Tab2 }
]
}
]默认子路由
除了使用redirect路由重定向,还可以使用默认子路由
默认子路由:如果children数组中,某个路由规则的path值为空字符串,则这条路由规则,叫做“默认子路由”。1
2
3
4
5
6
7
8
9
10{
// right页面的路由规则(父级路由规则)
path: '/right',
component: Right,
children: [
{ path: '', component: Tab1 },
{ path: 'tab1', component: Tab1 },//也可以不写这条规则,而是把tab1的路由标签改为/right
{ path: 'tab2', component: Tab2 }
]
}默认子路由和重定向都可以展示出children里面的某一个子组件。
动态路由
思考:有如下3个路由链接:
1 | <router-link to="/movie/1">电影1</router-link> |
定义如下3个路由规则:
1 | {path: '/movie/1', component: Movie } |
缺点:路由规则的复用性差
动态路由的概念
动态路由指的是:把 Hash地址 中可变的部分定义为参数项,从而提高路由规则的复用性。
在vue-router中使用英文的冒号( : )来定义路由的参数项。示例代码如下:1
2// 路由中的动态参数以︰进行声明,冒号后面的是动态参数的名称
{ path: '/movie/:id', component: Movie }将多个路由规则,合并成了一个,提高了路由规则的复用性
注意:路由链接的跳转地址是不能出现冒号:
的!<router-link to="/movie/1">电影1</router-link>
在组件中拿到动态参数项的值
this.$route
是路由的“参数对象”
this.$router
是路由的“导航对象”
要想拿到上面movie的id值应该通过:this.$route.params.id
为路由规则开启prop传参
简化拿参数的方式。这种方式和this.$route.params.id
是彼此独立的,想用哪个就用哪个
1 | // src/router/index.js |
拓展 query 和 fullPath
在 hash 地址中,/ 后面的参数项,叫做 “路径参数”
在路由“参数对象”中,需要使用this.$route.params
来访问路径参数1
2<router-link to="/movie/1">电影1</router-link>
<router-link to="/movie/2">电影2</router-link>在 hash 地址中,?后面的参数项,叫做 “查询参数”
在路由“参数对象”中,需要使用this.$route.query
来访问查询参数1
2<router-link to="/movie/1">电影1</router-link>
<router-link to="/movie/2?name=zs age=20">电影2</router-link>在
this.$route
中,path只是路径部分; fullPath是完整的地址
/movie/2
是 path 的值
/movie/2?name=zs age=20
是 fullPath 的值
路由导航
导航就是跳转的意思,组件之间的切换,它专业的术语叫导航。
声明式导航 & 编程式导航
在浏览器中,点击链接实现导航的方式,叫做声明式导航。
例如:
普通网页中点击a链接、vue 项目中点击router-link都属于声明式导航在浏览器中,调用API方法实现导航的方式,叫做编程式导航。
例如
普通网页中调用location.href
跳转到新页面的方式,属于编程式导航
vue-router 中的编程式导航API
vue-router(导航对象)提供了许多编程式导航的API,其中最常用的导航API分别是:
this.$router.push('hash地址')
跳转到指定 hash 地址,并增加一条历史记录this.$router.replace('hash地址')
跳转到指定的hash地址,并替换掉当前的历史记录this.$router.go(数值n)
n可以是正数也可以是负数,在浏览历史里面进行前进和后退$router.go
的简化用法
在实际开发中,一般只会前进和后退一层页面。因此 vue-router 提供了如下两个便捷方法:
(1)$router.back()
:在历史记录中,后退到上一个页面
(2)$router.forward()
:在历史记录中,前进到下一个页面
注意:在行内使用编程式导航跳转的时候,this必须要省略,否则会报错!
路由导航守卫 – 控制路由的访问权限
导航守卫可以控制路由的访问权限。
假设规定,当前项目中,main这个后台主页只有登陆以后才允许被访问(前提)
怎么证明你有没有登陆————token
可以读你的localStorage,看里面有没有token值,如果有就认为你已经是登录了,没有就认为你没有登陆。
全局前置守卫
前置:比如从a跳到b,还没跳过去,就会触发守卫。
每次发生路由的导航跳转时,都会触发全局前置守卫。因此,在全局前置守卫中,程序员可以对每个路由进行访问权限的控制:1
2
3
4
5//创建路由实例对象
const router = new VueRouter({ ... })
//调用路由实例对象的beforeEach方法,即可声明“全局前置守卫”
//每次发生路由导航跳转的时候,都会自动触发 fn 这个“回调函数”
router.beforeEach(fn)守卫方法的3个形参
全局前置守卫的回调函数中接收3个形参,格式为:1
2
3
4
5
6
7
8const router = new VueRouter({ ... })
// 全局前置守卫
router.beforeEach((to,from,next)=>{
// ro 是将要访问的路由的信息对象
// from 是将要离开的路由的信息对象
// next 是一个函数,调用next() 表示放行,允许这次路由导航
})next函数的3种调用方式
具体使用哪一种,看自己的需求
- 全局前置守卫控制访问权限简单示例vue的导航守卫中除了全局前置守卫之外,还有全局解析守卫、全局后置钩子、路由独享的守卫、组件内的守卫,共5种
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17// 为router实例对象,声明全局前置导航守卫
router.beforeEach(function(to, from, next) {
// 分析:
// 1. 要拿到用户将要访问的hash地址
// 2. 判断hash地址是否等于/main
if (to.path === '/main') { // 等于 /main ,证明需要登陆之后才能访问成功,
// 需要读取 localStorage 中的 token值
const token = localStorage.getItem('token')
if (token) {
next() // 有token值,则已登录 放行
} else {
next('/login') // 无 token值 则强制跳转到login登录页面
}
} else {
next() // 不等于则访问的不是后台主页,不需要登陆 直接放行 next()
}
})
其中,全局前置守卫的用法是最常见的,后面的几种后续会进行补充
案例练习
-
后台管理案例
-
SPA单页面应用程序 移动端 简单案例
实现下拉刷新、上拉加载更多功能、Vant组件库的使用配置:Babel、Router、CSS Pre-processors、Linter / Formatter、Vue 2.x
选择路由模式 – Use history mode for router? – Nhistory mode for router 需要和后端配合使用,兼容性比较差
#开头的hash值所表示的路由,通用性更强,低级还是高级的浏览器都支持css预处理器 – less
ESLint – Standard config 标准配置
Lint on save 在保存的时候进行格式的检查项目结构:
views文件夹如果某个组件,是通过路由进行动态展示和切换的,这种组件要放到views里面
如果某个组件不是通过路由切换的,是一个可复用的组件,那么这个组件要放到components里面
Vant组件库
轻量、可靠的移动端组件库
Vant2官方文档(适用于 Vue2 开发) Vant4官方文档(适用于 Vue3 开发)
安装
1
2
3
4
5# Vue 3 项目,安装最新版 Vant:
npm i vant -S
# Vue 2 项目,安装 Vant 2:
npm i vant@latest-v2 -S导入组件
我们选择最便捷的方式 – 导入所有组件虽然官方推荐的做法是:自动按需引入组件。但是配起来太复杂了,成本太高了
引入所有组件会增加代码包体积,但是开发的时候我们怎么快怎么来,不用考虑体积的问题
在发布的时候,我们可以进行项目体积的优化,可以直接把Vant从项目里面抽出去1
2
3
4
5
6// main.js
import Vue from 'vue';
import Vant from 'vant';
import 'vant/lib/index.css';
Vue.use(Vant);使用
查阅官方文档即可
Vant2官方文档(适用于 Vue2 开发)
Vant4官方文档(适用于 Vue3 开发)
注意:在使用Vant组件的时候,如果某个组件的某个属性默认值是false,希望把它改成true,直接把这个属性写上就可以了
如:<van-nav-bar title="标题" fixed placeholder />
相当于<van-nav-bar title="标题" :fixed='ture' :placeholder='true' />
这里给属性值类型是布尔值,所以要用v-bind绑定,否则是字符串覆盖Vant组件的样式: /deep/ 样式穿透
还可以通过Vant组件库提供的定制主题,来直接改变组件的样式,这样在每个组件使用该组件都不需要再去修改。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26// 在main.js中 引入全部样式
import 'vant/lib/index.less';
// vue.config.js
// 这个文件是 vue-cli 创建出来的项目的配置文件
// 在vue.config.js 这个配置文件中,可以对整个项目的打包、构建进行全局性的配置
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
css: {
loaderOptions: {
less: {
// 若 less-loader 版本小于 6.0,请移除 lessOptions 这一级,直接配置选项。
lessOptions: {
modifyVars: {
// 直接覆盖变量
// 这里是覆盖了 NavBar 导航栏 的背景色
'nav-bar-background-color': 'red' // #007bff
// 或者可以通过 less 文件覆盖(文件路径为绝对路径)
// hack: `true; @import "your-less-file-path.less";`
}
}
}
}
}
})缺点:需要修改配置文件,必须重启打包服务器,太过麻烦,所以了解即可,实际开发不会这么使用
而是通过 less 文件覆盖进行主题的定制:1
hack: `true; @import "your-less-file-path.less";`
好处:不用重启打包服务器,直接改就能生效
通过less文件覆盖进行主题定制
如:在src目录下新建一个theme.less
1 | // 在theme.less文件中,覆盖Vant官方的less变量值 |
然后配置vue.config.js文件
1 | // 这个文件是 vue-cli 创建出来的项目的配置文件 |
vue.config.js 配置文件
这个文件是 vue-cli 创建出来的项目的配置文件
在这个配置文件中,可以对整个项目的打包、构建进行全局性的配置
项目开发完成之后,可以npm run build进行打包
最终项目里面会有个dist文件夹,里面有个index.html首页
但是有个问题:我们直接进入dist目录,双击这个首页打开,是看不到效果的。
因为:默认情况下,我们运行npm run build打包生成的dist,里面的这些文件,只能发布到服务器上,通过http协议才可以正常被打开。而双击打开的是file协议,所以看不到效果
如果想要看到效果,需要做一下打包发布的配置:vue.config.js-publicPath
在vue.config.js配置文件中设置publicPath为’./‘,再次打包文件,即可在文件夹中双击打开
1 | // ... |
publicPath
部署应用包时的基本 URL。
默认情况下,Vue CLI 会假设你的应用是被部署在一个域名的根路径上,例如 https://www.my-app.com/
如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.my-app.com/my-app/,则设置 publicPath 为 /my-app/ 。这个值也可以被设置为空字符串 (‘’) 或是相对路径 (‘./‘),这样所有的资源都会被链接为相对路径,这样打出来的包可以被部署在任意路径,也可以用在类似 Cordova hybrid 应用的文件系统中。
相对路径的 publicPath 有一些使用上的限制。在以下情况下,应当避免使用相对 publicPath:
- 当使用基于 HTML5 history.pushState 的路由时;
- 当使用 pages 选项构建多页面应用时。
拓展
hash地址注意点
hash地址里面字母都要是小写,url地址里面不要出现大写字符或字母。
除非是一些 搜索关键字 可以出现大写
有权限的hash地址
在导航守卫 – 全局前置守卫中
这个if是判断我们访问的是否是一个有权限的hash地址:if (to.path === '/main')
1 | router.beforeEach(function(to, from, next) { |
如果我们项目中有多个页面,都需要访问权限,这一个判断肯定满足不了我们的需求
我们可以在后面加 或 |
:
1 | if (to.path === '/main' || to.path === '/home' || to.path === '/home/users'){} |
但是条件会变的越来越长
我们还可以通过数组:
1 | const pathArr = ['home','/home/users','/home/rights'] |
后面有任何的地址,都可以放到数组里面去
如果觉得多了以后,数组也会变的特别长,可以把这个数组单独处理为js文件,需要的时候再导入过来。如:
1 | // src/router/pathArr.js |
使用meta属性进行权限处理
可以配置meta属性,使用前置守卫进行判断是否需要进行权限处理,会方便很多
配置
meta
属性
在路由配置中,可以在每个路由的meta
属性中指定需要进行权限处理的信息。例如:1
2
3
4
5
6
7
8
9
10
11
12
13const router = new VueRouter({
routes: [
{
path: '/admin',
component: Admin,
meta: {
requiresAuth: true,
roles: ['admin'] // 用于指定可以访问特定路由的用户的角色
}
},
// 其他路由...
]
})在这个例子中,
/admin
路由需要进行权限处理,只有具有admin
角色的用户才能访问。使用前置守卫
在 Vue Router 中,使用beforeEach
前置守卫来拦截导航并执行权限检查:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15router.beforeEach((to, from, next) => {
if (to.meta.requiresAuth) {// 检查是否需要进行权限处理
if (isAuthenticated()) {// 检查用户是否已登录
if (hasRequiredRoles(to.meta.roles)){ // 检查用户是否具有所需的权限
next()// 允许导航
}else {
next('/no-access') // 无权限,重定向到无权限页面
}
} else {
next('/login')// 未登录,重定向到登录页面
}
} else {
next() // 不需要权限处理,允许导航
}
})其中,isAuthenticated() 和 hasRequiredRoles() 是自定义函数,用于检查用户是否已登录以及是否具有所需的权限。
isAuthenticated()函数 :用于检查用户是否已登录
通常用于判断用户是否携带有效的 token。
实际应用中,可以根据自己的后端 API 设计来实现 isAuthenticated() 函数:- 从本地存储(如 localStorage 或 sessionStorage)中获取用户的 token。
- 向后端 API 发送一个请求,携带用户的 token。
- 后端 API 验证 token 的有效性。
- 如果 token 有效,后端 API 返回成功响应。
- isAuthenticated() 函数返回 true,表示用户已登录。
- 否则,isAuthenticated() 函数返回 false,表示用户未登录或 token 无效。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24function isAuthenticated() {
const token = localStorage.getItem('token')// 从本地存储中获取 token
if (token) {// 如果 token 存在,向后端 API 发送请求
return fetch('/api/auth/verify-token', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`
}
})
.then(res => res.json())
.then(data => { // 'data' 是一个 JavaScript 对象,包含从服务器接收到的 JSON 数据
if (data.success) {// 如果 token 有效,返回 true
return true
} else {// 如果 token 无效,返回 false
return false
}
})
.catch(err => {// 如果请求失败,返回 false
return false
})
} else {// 如果 token 不存在,返回 false
return false
}
}.then(res => res.json())
是 JavaScript Promise 链中的一个回调函数。
作用: 将服务器返回的 HTTP 响应对象 (res)————服务器响应的主体部分(JSON 字符串) 转换为一个纯 JavaScript 对象,并将其传递给下一个 .then() 回调函数。
注意:
只有当服务器响应的 Content-Type 头部设置为application/json
时,res.json()
方法才能正常工作。
如果服务器响应的主体部分不是有效的 JSON 字符串,res.json()
方法会抛出一个错误。
hasRequiredRoles() 函数用于检查用户是否具有访问特定路由所需的权限。
它的实现方式取决于你的具体应用程序和后端 API 设计。
一种常见的方法:- 从本地存储(如 localStorage 或 sessionStorage)中获取用户的角色。
- 将用户的角色与路由配置中指定的所需角色进行比较。
- 如果用户具有所有必需的角色,则返回 true,表示用户具有访问权限。
- 否则,返回 false,表示用户没有访问权限。
1
2
3
4
5
6
7
8
9
10function hasRequiredRoles(requiredRoles) {
const userRoles = localStorage.getItem('roles')// 从本地存储中获取用户的角色
// 将用户的角色与所需的权限进行比较
for (let i = 0; i < requiredRoles.length; i++) {
if (!userRoles.includes(requiredRoles[i])) {
return false
}
}
return true // 如果用户具有所有必需的角色,返回 true
}
另一种方法:
向后端 API 发送一个请求,携带用户的 token 和路由的所需角色。后端 API 检查用户的权限并返回一个响应,指示用户是否具有访问权限。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24function hasRequiredRoles(requiredRoles) {
const token = localStorage.getItem('token')// 从本地存储中获取用户的 token
// 向后端 API 发送请求
return fetch('/api/auth/check-permissions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({
requiredRoles: requiredRoles
})
})
.then(res => res.json())
.then(data => {
if (data.success) {// 如果用户具有访问权限,返回 true
return true
} else { // 如果用户没有访问权限,返回 false
return false
}
})
.catch(err => {
return false // 如果请求失败,返回 false
})
}
Less变量
Less 是一种可编程的样式语言。
@
是在less语法里面,专门定义变量的一种格式
支持我们以编程的方式来写CSS代码
1 | @width: 10px; |
编译为:
1 | #header{ |