Vue 前端开发(下篇)
❖ Vue常用指令之数据双向绑定
❖ 实例生命周期钩子
❖ Vue Cli脚手架
❖ Vue组件
❖前后端数据交互:Axios
❖ Vue路由:Vue Router
❖ Vue UI组件库:Element Plus
1 Vue常用指令之数据双向绑定
-
v-model
-
常用指令总结
1.1 v-model
双向数据绑定:通过前面学习知道Vue是数据驱动的,数据驱动有一个精髓之处是数据双向绑定,即当数据发生变化的时候,视图也就发生变化,当视图发生变化的时候,数据也会跟着同步变化。
1.1.1 v-model:表单输入
v-model
指令提供表单输入绑定,可以在 <input>、<textarea>
及 <select>
元素上创建双向数据绑定。
v-model
指令其实是一个语法糖,背后本质上包含 v-bind(背后其实就是绑定了一个 value 的属性,从而实时获取对应的值)
和 v-on(涉及到触发属性输出,也就是当在输入框输入之后才会触发)
两个操作。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue测试</title>
<script src="https://unpkg.com/vue@3"></script>
</head>
<body>
<div id="hello-vue">
<!-- 定义 input 绑定 v-model 也就是说用户往 input 中输入的内容都会更新到 message 变量中 -->
<input type="text" v-model="message">
<!-- 通过 p 标签输出 message -->
<p>p标签:{{ message }}</p>
</div>
<script>
const HelloVueApp = {
data() {
return {
message: 'hello-vue',
}
}
}
Vue.createApp(HelloVueApp).mount("#hello-vue")
</script>
</body>
</html>
浏览器访问可以看到在输入框中默认就是 hello-vue 的内容
往输入框填写内容,可以看到 p 标签的内容也发生了变化
这就是双向绑定的一种效果,不管标签里面的值发生变化还是数据发生变化,都会双向同步
1.1.2 v-model:单选
单选框(radio):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue测试</title>
<script src="https://unpkg.com/vue@3"></script>
</head>
<body>
<div id="hello-vue">
<!-- 单选指定两个 input 标签的 name 都为 dev,从而实现只能够选择一个,并且将获取的内容基于 v-model 存储值 result 中 -->
<input type="radio" name="dev" value="Go" v-model="result">Go<br>
<input type="radio" name="dev" value="Vue" v-model="result">Vue<br>
<!-- 浏览器中输出 result 当前所选择的内容 -->
<p>当前选择:{{result}}</p>
</div>
<script>
const HelloVueApp = {
data() {
return {
// 定义空变量,用于存放所选择的内容
result: '',
}
}
}
Vue.createApp(HelloVueApp).mount("#hello-vue")
</script>
</body>
</html>
浏览器访问,选择 Go 就会在当前选择输入所选择的内容
选择 Vue ,这次变为了 vue
1.1.3 v-model:多选框
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue测试</title>
<script src="https://unpkg.com/vue@3"></script>
</head>
<body>
<div id="hello-vue">
<!-- 针对 select 标签做一个双向绑定,并且将获取的内容基于 v-model 存储值 result 中-->
<select v-model="result">
<!-- 定义多个 option 标签作为所选择的内容 -->
<option value="未选择">未选择</option>
<option value="Go">Go</option>
<option value="Vue">Vue</option>
<option value="K8s">K8s</option>
<option value="Docker">Docker</option>
</select>
<!-- 浏览器中输出 result 当前所选择的内容 -->
<p>当前选择:{{result}}</p>
<br>
</div>
<script>
const HelloVueApp = {
data() {
return {
// 定义空变量,用于存放所选择的内容
result: '',
}
},
}
Vue.createApp(HelloVueApp).mount("#hello-vue")
</script>
</body>
</html>
浏览器点击下拉框可以看到当前有这么多选择性
随机选择一个,浏览器直接将选择的数据进行输入,其他下拉框以此类推
1.1.4 v-model:登录案例
我们都知道登录一个页面都包含用户名,密码,还有一个登录按钮,而在这个示例中需要实现一个登录逻辑。就是获取输入的用户名和密码然后进行判断最后向服务端进行提交,最后服务端入库验证是否有该用户对应的信息;如果没有则就向前端提示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>测试</title>
<script src="https://unpkg.com/vue@3"></script>
</head>
<body>
<div id="hello-vue">
<h1>欢迎访问管理后台</h1>
<!-- 通过 form 标签创建登录表单 -->
<form action="#">
<!-- 双向绑定,获取用户名密码,并存放到 data() 中定义的 userInfo 对象中 -->
用户名:<input type="text" v-model="userInfo.username">
密 码:<input type="password" v-model="userInfo.passwrod">
<input type="button" @click="loginBtn" value="登录">
</form>
<!-- 引用 notice 前端输出 -->
<p style="color: red" v-if="notice">用户名或密码不能为空!</p>
</div>
<script>
const HelloApp = {
data() {
return {
// 创建 userInfo 对象,并且将两个元素都设置为空值从而获取用户输入的信息,最后再将 userInfo 提交服务端即可
userInfo: {
username: '',
passwrod: ''
},
// 定义 notice 变量值为 false 用于用户名密码为空时进行前端提示
notice: false,
}
},
methods: {
// 定义 loginBtn 方法用于点击登录时触发下面的 if 判断
loginBtn() {
// 如果说 username 和 password 任意一个数据的值为空那么我们就需要在前端 p 标签中的 notice 进行提示
if (this.userInfo.username == '' || this.userInfo.passwrod == ''){
// 通过 this 关键字给 notice 变量赋值,如果值为空就给 notice 赋值为 true,然后直接输出 p 标签中内容
this.notice = true
} else if (this.userInfo.username != '' && this.userInfo.passwrod != '') {
// 如果说用户名和密码都不为空 this.notice = false 不在提示 p 标签中内容
this.notice = false
// 这一块就是将获取的用户数据提交至服务端,但是这里是输出在浏览器 console 上
console.log(this.userInfo.username,this.userInfo.passwrod)
}
}
},
}
Vue.createApp(HelloApp).mount('#hello-vue');
</script>
</body>
</html>
浏览器访问不在输入内容是演示,可以看到对应提示
浏览器访问输入空密码演示:这里我们没有输入密码直接提示对应的回显
这次在浏览器的 console 中能够看到对应的用户输入登录信息
1.2 常用指令总结
常用指令:
v-text
:没有闪烁问题,数据加载成功后,清空元素的内容,将新数据覆盖上去v-html
:输出 html 格式的字符串,会自动解析成 htmlv-cloak
:解决插值表达式在页面初始加载时的闪烁问题,在数据加载成功钱隐藏,成功后显示v-on
:监听事件,缩写@
v-bind
:给元素动态绑定属性,缩写:
v-model
:数据双向绑定,只能用于表单元素v-if
:显示或隐藏元素,每次都会删除或创建,性能有一定开销v-show
:显示或隐藏元素,通过display
属性实现,适合频繁切换的场景v-for
:循环遍历,需要绑定 key 属性并唯一
2 实例生命周期钩子
生命周期是指 Vue 实例从创建到销毁的过程。就是 vue 实例从开始创建、初始化数据、编译模板、挂载 Dom、渲染->更新->渲染、卸载等⼀系列过程,在vue⽣命周期中提供了⼀系列的⽣命周期函数,如图所⽰。
如上图:
在整个程序顶部定义一个 vue 实例
- 第一阶段:
init
初始化,并执行一个 beforecreate 阶段,然后就是进行创建并初始化钩子,到了 create 这一步就是指的自动创建这个函数。因为这时候 vue 已经创建成功了。init 阶段主要就是 vue 的实例初始化 - 第二阶段:
beforeMount
当 vue 创建成功就需要渲染代码中的东西到 web 页面中,当渲染完成之后就开始执行mounted
钩子函数将一些组件还有其他数据渲染到页面中 - 第三阶段:
beroreUnmount
这个是在 mounted 位置,并且有一个beforeUpdate
这一块主要是在工作的时候页面打开期间的这么一个循环,就是说当我们的页面已经挂上了并且当用户访问的时候后台就会一直工作,这一块就是当 vue 中data(){}
函数里面的数据发生变化就会执行这里面的 update 操作,当页面关闭之后就会将 vue 的实例进行销毁 - 第四阶段:
Unmounted
钩子,当关闭页面之后销毁 vue
2.1 created 演示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>测试</title>
<script src="https://unpkg.com/vue@3"></script>
</head>
<body>
<div id="hello-vue">
</div>
<script>
const HelloApp = {
// 这里创建一个 vue 的实例
created() {
console.log("vue 创建实例")
}
}
Vue.createApp(HelloApp).mount('#hello-vue');
</script>
</body>
</html>
在浏览 console 中可以查看
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>测试</title>
<script src="https://unpkg.com/vue@3"></script>
</head>
<body>
<div id="hello-vue">
</div>
<ul>
<li v-for="i in computer" :key="i">{{i}}</li>
</ul>
<script>
const HelloApp = {
data: {
computer: ""
},
methods:{
// 在方法定义 getData 函数,并定义一个数组赋值给 data 中的 computer
getData() {
computer = ["主机","显示器","键盘"]
this.computer = computer
}
},
}
Vue.createApp(HelloApp).mount('#hello-vue');
</script>
</body>
</html>
在上面的代码中我定义了一组数组,但是在浏览器上可以看到并没有刷新出来,因为像 methods 方法中的函数都是用于触发的时候
所以这时候我将代码进行改造,通过 created 钩子实现初始化 vue 的渲染,也就是说当我们打开页面就会显示。只需要在 created()
调用 getData()
即可
2.2 mounted 演示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>测试</title>
<script src="https://unpkg.com/vue@3"></script>
</head>
<body>
<div id="hello-vue">
</div>
<script>
const HelloApp = {
mounted() {
console.log("Vue 实例挂载并渲染完成")
}
}
Vue.createApp(HelloApp).mount('#hello-vue');
</script>
</body>
</html>
3 VueCli 脚手架
3.1 Vue Cli 脚手架介绍
到目前为止,已经会了Vue基本使用,但这种在HTML引用Vue.js的方式,简单的页面还是没问题的,如果用Vue开发整个前端项目,组建Vue项目结构及配置还是比较复杂的,例如引入各种js文件、打包上线等。因此,为了提高开发效率,官方开发了VueCli脚手架快捷搭建开发环境。
Vue CLI 是一个基于 Vue.js 进行快速开发的完整系统,其实他就是一个命令行工具,提供:
-
通过 @vue/cli 实现的交互式的项目脚手架。
-
通过 @vue/cli + @vue/cli-service-global 实现的零配置原型开发。
-
一个运行时依赖 (@vue/cli-service),该依赖:
-
可升级;
-
基于 webpack 构建,并带有合理的默认配置;
-
可以通过项目内的配置文件进行配置;
-
可以通过插件进行扩展。
-
一个丰富的官方插件集合,集成了前端生态中最好的工具。
-
一套完全图形化的创建和管理 Vue.js 项目的用户界面。
Vue CLI 致力于将 Vue 生态中的工具基础标准化。它确保了各种构建工具能够基于智能的默认配置即可平稳衔接,这样你可以专注在撰写应用上,而不必花好几天去纠结配置的问题。
3.2 认识 NPM
在使用 Vue Cli 之前,需先了解一些关于NPM的知识点:
-
NPM(Node Package Manager,Node包管理器),存放 JavaScript 代码共享中心,是目前最大的JavaScript 仓库。类似于 Linux yum 仓库。
-
可能你会联想到 Node.js,Node.js 是服务端的 JavaScript,类似于 Gin、Django,NPM 是基于 Node.js 开发的软件。
-
随着 Node.js 兴起,生态圈的JS库都纷纷向 NPM 官方仓库发布,所以现在,大都是使用 npm install 命令来安装 JS 库,而不必再去它们官网下载了。
3.2.1 安装 NPM
安装 Node.js,默认已经内置 npm,下载对应软件包直接安装即可。http://nodejs.cn/download/
NPM 常用命令:
1.wget 下载
oot@ubuntu:~# cd /usr/local
root@ubuntu:/usr/local# mkdir node
root@ubuntu:/usr/local# cd node/
# 下载
root@ubuntu:/usr/local/node# wget https://npmmirror.com/mirrors/node/v16.16.0/node-v16.16.0-linux-x64.tar.xz
# 解压
root@ubuntu:/usr/local/node# tar xf node-v16.16.0-linux-x64.tar.xz
# 软连接
root@ubuntu:/usr/local/node# ln -s /usr/local/node/node-v16.16.0-linux-x64/bin/npm /usr/local/bin/npm
root@ubuntu:/usr/local/node# ln -s /usr/local/node/node-v16.16.0-linux-x64/bin/node /usr/local/bin/node
然后直接全程下一步即可,安装完毕之后通过 cmd 查看是否安装完成
root@ubuntu:/usr/local/node# npm -v
8.11.0
装完 npm 之后还需要替换为国内源,因为默认的话是国外的源
# 配置淘宝 npm 仓库
root@ubuntu:/usr/local/node# npm config set registry https://registry.npmmirror.com
# 查看仓库替换成功
root@ubuntu:/usr/local/node# npm config get registry
https://registry.npm.taobao.org/
3.3 Vue Cli 脚手架使用
Vue Cli脚手架使用步骤:
-
命令安装:
npm install -g @vue/cli
-
检查版本:
vue -V
-
创建项目:
vue create <项目名称>
-
运行项目,访问
3.3.1 创建一个目录
1 安装 vue/cli
root@ubuntu:~# npm install -g @vue/cli
2 检查版本
# 创建软连接
root@ubuntu:~# ln -s /usr/local/node/node-v16.16.0-linux-x64/bin/vue /usr/local/bin/vue
root@ubuntu:~# vue -V
@vue/cli 5.0.8
3 创建项目
# 创建项目,键盘上下键可以选择,空格确定选择
root@ubuntu:~# vue create hello-vue
00h00m00s 0/0: :
Vue CLI v5.0.8
Failed to check for updates
? Please pick a preset:
Default ([Vue 3] babel, eslint)
Default ([Vue 2] babel, eslint)
❯ Manually select features # 这里我通过手动配置,并回车
Vue CLI v5.0.8
Failed to check for updates
? Please pick a preset: Manually select features
? Check the features needed for your project: (Press <space> to select, <a> to toggle all, <i> to
invert selection, and <enter> to proceed)
◉ Babel
◯ TypeScript
◯ Progressive Web App (PWA) Support
❯◉ Router # 空格选择 router
◯ Vuex
◯ CSS Pre-processors
◉ Linter / Formatter
◯ Unit Testing
◯ E2E Testing
# 选择 vue 版本
Vue CLI v5.0.8
Failed to check for updates
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, Router, Linter
? Choose a version of Vue.js that you want to start the project with
❯ 3.x # 选择 3 版本
2.x
# 选择路由
Vue CLI v5.0.8
Failed to check for updates
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, Router, Linter
? Choose a version of Vue.js that you want to start the project with 3.x
? Use history mode for router? (Requires proper server setup for index fallback in production) (Y/n) # 选择 n 即可直接使用
# 选择代码校验
? Pick a linter / formatter config:
ESLint with error prevention only
ESLint + Airbnb config
ESLint + Standard config
❯ ESLint + Prettier # 选择最后一个
# 什么时候进行代码校验
? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection,
and <enter> to proceed)
❯◉ Lint on save # 选择保存之后就检查
◯ Lint and fix on commit
# 如何保存配置
? Where do you prefer placing config for Babel, ESLint, etc.?
In dedicated config files
❯ In package.json # 保存到 package.json 中
# 选择是否保存本次配置
? Save this as a preset for future projects? (y/N) # 这里选择 n
# 安装完毕之后就会出现下面内容
✨ Creating project in /root/hello-vue.
🗃 Initializing git repository...
⚙️ Installing CLI plugins. This might take a while...
added 849 packages in 32s
🚀 Invoking generators...
📦 Installing additional dependencies...
added 101 packages in 5s
⚓ Running completion hooks...
📄 Generating README.md...
🎉 Successfully created project hello-vue.
👉 Get started with the following commands:
# 并输出这两个命令
$ cd hello-vue
$ npm run serve
4 启动项目
root@ubuntu:~# cd hello-vue/
root@ubuntu:~/hello-vue# npm run serve
DONE Compiled successfully in 3882ms 9:44:21 am
# 提示下面链接
App running at:
- Local: http://localhost:8080/
- Network: http://10.0.0.134:8080/
Note that the development build is not optimized.
To create a production build, run npm run build.
5 浏览器访问
6 通过 goland 工具可以看到当前的目录结构
3.3.2 通过 goland 启动项目
默认情况下 goland 是没有对 vue 脚手架项目做启动项,所以我们需要自行添加对应的配置
1 点击添加配置
2 点击 + 号
3 点击 npm,这个 npm 就是用来运行 vue 项目的
4 找到对应的项目 json,以及定义脚本名称、对应软件包、node 解析器等,最后点击确定
5 这时候可以看到左上角就有对应的红色运行按钮
6 点击运行之后可以看到当前已经运行
7 浏览器访问
3.4 项目目录
上面这张图就是当前 hello-vue 对应的项目目录结构:
- node_modules:保存的对应依赖包
- pubic:存放当前站的 favicon、和当前站点的描述信息
- src:用于开发项目的真正目录,源码目录、和 vue 开发目录
- assets:存放资源,如 logo 、图片、css 等都在这里面
- components:主要用来存放公共组件
- routes:我们在创建项目的时候所对应的路由
- views:网站具体的页面都存放在此,也就是后面开发的页面我们都需要在此开发
- App.vue:项目的根组件,也是一个项目的入口
- main.js:项目的配置文件,第三方库都是通过这个文件进行导入
- package.json:用来保存当前项目的包
4 Vue 组件
-
介绍
-
文件格式
-
使用
-
注册
-
传参
4.1 介绍
组件:
一段独立的,能代表页面某一个部分的代码片段,拥有自己独立的数据、JavaScript 脚本、以及 CSS 样式。组件是可复用的 Vue 实例,在开发过程中可以把经常重复的功能,封装为组件,达到快捷开发的目的。
组件的好处:
- 提高开发效率
- 方便重复使用
- 易于管理和维护
什么情况下使用组件:
一般在我们写一个页面并且可能多个地方会套用同一个页面代码,多个地方使用到的页面就可以封装成一个组件。
或者该项目所需的页面代码量巨大不易于维护,这时候我们也可以通过组建的方式进行拆分,有点类似于 go 里面的函数,从而实现解耦
如上图:
上图是我们开发一个页面的大概效果,通常一个应用会以一棵嵌套的组件树的形式来组织,如图所示。例如,你可能会有页头、侧边栏、内容区等组件,每个组件又包含了其它的像导航链接、博文之类的组件。
4.2 组件:文件格式
Vue单文件组件(又名 *.vue 文件,缩写为 SFC)是一种特殊的文件格式,它允许讲Vue组件的模板、逻辑与样式封装在单个文件中。
正如所见,Vue SFC 是经典的 HTML、CSS 与 JavaScript 三个经典组合的自然延伸。每个 *.vue 文件由三种类型的顶层代码块组成:<template>
、<script>
与 <style>
:
-
<template>
定义了组件的模板。这里面需要写入 html 的页面 -
<script>
是一个标准的 JavaScript 模块。它应该导出一个 Vue 组件定义作为其默认导出。 -
<style>
定义了与此组件关联的 CSS。
如当前创建的 hello-vue 项目,我们可以看到他的 views 目录下有 HomeView.vue
文件,通过查看该文件可以看到它在 import
处引入了 /components/HelloWorld.vue
文件
接着我们可以看到对应 components 目录下的 HelloWorld.vue 文件其实就是 vue 项目的 web 页面
由此可以得出实际上 HomeView.vue
其实就是主组件,而 /components/HelloWorld.vue
就是我们的子组件,只是通过引入的方式给展示了
4.3 组件:使用
- 第一步:开发组件,就是创建以 *.vue 开头的文件
- 第二步:注册组件
- 第三步:使用组件
使用具体流程:
1、在 src/components
目录里开发一个子组件文件(首字母大写如HelloWorld.vue
)
2、然后通过父组件进行导入,在父组件里引用子组件 import xxx from‘xxx’
3、在默认导出里注册组件
4、在 template
模板里使用组件
4.3.1 局部注册组件使用
4.3.1.1 关闭 vue 语法检查功能
因为不关闭该项就会提示语法不合格从而程序运行失败,关闭 eslint(是 js 的语法测试工具)
1 打开 vue.config.js 文件
2 添加如下代码 lintOnSave: false,
即可
4.3.1.2 创建 vue 子组件
1 点击创建 vue 组件
root@ubuntu:~/hello-vue/src/components# ls TestPkg.vue
TestPkg.vue
# 这里我创建了一个 TestPkg.vue 组件
2 创建之后默认会生成一个 vue 的初始化代码内容如下:
<template>
</template>
<script>
export default {
name: "TestPkg"
}
</script>
<style scoped>
</style>
3 编写 test.vue 文件
<template>
<!-- 引入 style 中 cc 类 -->
<div class="cc">
<!-- 引入 data 中定义的 message 变量 -->
<h1> {{message}} </h1>
</div>
</template>
<script>
// 里面默认就是 vue 的语法
export default {
name: "TestPkg",
// 定义 data 并返回 message 变量
data() {
return {
message: "hello vue!"
}
}
}
</script>
<style scoped>
.cc {
background: red;
}
</style>
当我们编写完了 vue 的子组件之后我们就需要引入到父组件中
4.3.1.3 父组件引入子组件
1 这里我在 HomeView.vue 父组件中导入 test 子组件
<template>
<div class="home">
<img alt="Vue logo" src="../assets/logo.png" />
<HelloWorld msg="Welcome to Your Vue.js App" />
<!-- 3.引用 TestPkg 子组件 -->
<TestPkg></TestPkg>
</div>
</template>
<script>
// @ is an alias to /src
import HelloWorld from "@/components/HelloWorld.vue";
// 1.导入 test 组件,"@/components/TestPkg.vue" 为该子组件的相对路径
import TestPkg from "@/components/TestPkg.vue";
export default {
name: "HomeView",
components: {
HelloWorld,
// 2.注册 TestPkg 组件
TestPkg,
},
};
</script>
2 启动程序浏览器验证,可以看到就有一个红色的 hello vue! 的渲染
4 其他父组件引用子组件
当然 testpkg 子组件可以在任何父组件中使用,如 AboutView.vue
父组件中使用
<template>
<div class="about">
<h1>This is an about page</h1>
<!-- 3.引用 TestPkg 子组件 -->
<TestPkg></TestPkg>
</div>
</template>
<script>
// 1.导入 test 组件,"@/components/TestPkg.vue" 为该子组件的相对路径
import TestPkg from "@/components/TestPkg.vue"
export default {
name: "AboutView",
components: {
// 2.注册 TestPkg 组件
TestPkg,
},
};
</script>
5 浏览器查看,点击 About 即可查看 hello vue!
以上就是演示如何使用组件
4.4 组件:注册组件
为了能在模板中使用,这些组件必须先注册以便 Vue 能够识别。这里有两种组件的注册类型:全局注册和局部注册。上述是局部注册,只能在当前模板中使用。
-
全局注册:声明一次,在任何 vue 文件模板中使用,一般使用该组件的地方多时使用
-
局部注册:在使用组件的 vue 文件中声明和使用,一般只需要解耦代码时使用,所谓的全局注册其实就是在
main.js
文件中注册,只要是这个文件中注册的都为全局
4.4.1 全局注册使用
1 打开 main.js
2 注册 TestPkg 组件
import { createApp } from "vue";
// 导入 App 组件,引用 "./App.vue" 文件
import App from "./App.vue";
import router from "./router";
// 1.导入 testPkg 组件
import TestPkg from "@/components/TestPkg";
// 基于 App 组件并赋值 app 变量
const app = createApp(App);
app.use(router).mount("#app")
// createApp(App).use(router).mount("#app"); 通过上面的写法来实现该方法
// 注册全局组件
app.component('TestPkg',TestPkg)
3 当注册了全局组成组件之后就可以在任何文件中使用,如这里在 aboutView 文件中使用
<template>
<div class="about">
<h1>这是一个关于的页面</h1>
<!-- 直接导入 TestPkg 全局组件-->
<TestPkg></TestPkg>
</div>
</template>
4 浏览器访问,可以看到直接引用了 TestPkg
组件
4.5 组件:传参
学习了组件用法,就像一种嵌套引用关系,在这个关系中,经常会涉及相互传数据的需求,现在父组件和子组件只是简单的导入,但是有的时候需要涉及到数据的传参,比如有时候需要将父组件的数据传递给子组件,或者子组件传递给父组件,那么我们该如何实现组件间的传参
父、子组件的关系可以总结为: 父组件向子组件通过 prop
参数向子组件传递,子组件通过 EmitEvents
向父组件传递。
父组件通过 prop 给子组件下发数据,子组件通过 给父组件发送消息,如下图所示:
4.5.1 实现传参
当前 vue 首页结构,那么下面我就如何实现传参
4.5.1.1 父传子
父传子:在默认页面中,也用到了父传子,在父组件 Home.vue 中给引用的组件传入一个静态的值,子组件通过props 属性接收,并在模板中使用。
现在需要在 about 文件中定义参数,并实现传递给 TestPkg 子组件,从而实现父传子并渲染
1 这里对 about.vue 文件进行编辑
<template>
<div class="about">
<h1>这是一个关于的页面</h1>
<!-- 直接导入 TestPkg 全局注册组件,并向 TestPkg 子组件传递 info -->
<TestPkg info="你好,我是父组件数据"></TestPkg>
</div>
</template>
2 在 TestPkg.vue 子组件引用 msg
<template>
<!-- 引入 style 中 cc 类 -->
<div class="cc">
<!-- 引入 data 中定义的 message 变量 -->
<h1> {{message}} </h1>
<!-- 引入 props 接收 about 父组件 info 数据 -->
<h2>这是父组件传递过来的:{{ info }}</h2>
</div>
</template>
<script>
// 里面默认就是 vue 的语法
export default {
name: "TestPkg",
// 通过 props 接收 about 父组件 info 数据
props: {
info: String
},
// 定义 data 并返回 message 变量
data() {
return {
message: "hello vue!"
}
}
}
</script>
<style scoped>
.cc {
background: red;
}
</style>
3 浏览器访问,当前可以看到已经实现父组件传递子组件
4.5.1.1.1 script 的方式实现父传子
1 当然也可以通过 script
的方式传递,如下修改 about.vue 代码,无须修改 TestPkg.vue 代码
<template>
<div class="about">
<h1>这是一个关于的页面</h1>
<!-- 直接导入 TestPkg 全局注册组件,并向 TestPkg 子组件传递 info ,:info 是一种绑定写法这里是绑定下面的 info 变量 -->
<TestPkg :info="info"></TestPkg>
</div>
</template>
<script>
export default {
data(){
return {
// 定义 info 变量并将该变量传递给 div 标签中的 TestPkg 标签中的 :info
info: "screipt 传递父组件数据!",
}
}
}
</script>
2 浏览器渲染已经实现了引用 info 变量修改
4.5.1.1.2 数组的方式实现父传子
1 当然在 script 中不仅可以传递变量,也可以传递其他数据类型,比如这里我传递一个数组给子组件
<template>
<div class="about">
<h1>这是一个关于的页面</h1>
<!-- 直接导入 TestPkg 全局注册组件,并向 TestPkg 子组件传递 info -->
<TestPkg :info="info" ></TestPkg>
</div>
</template>
<script>
export default {
data(){
return {
// 定义 info 数组并将该变量传递给 div 标签中的 TestPkg 标签中的 :info
info:[
"张三",
"23 岁",
"男",
]
}
}
}
</script>
2 修改 TestPkg.vue 中的代码,实现对数组的遍历,如下图只需将 info 的数据类型该为 array
3 浏览器显示
当然对象也可以实现数据的传递,这里不在过多演示
4.5.1.2 子传父
在下面的代码中绑定一个按钮,因为只有在按钮中才能够实现事件,也就是说当我们点击这个按钮的时候子组件就会将数据传递个父组件
1 编写 TestPkg.vue 子组件代码
<template>
<!-- 引入 style 中 cc 类 -->
<div class="cc">
<button @click="btn">传递数据到父组件</button>
</div>
</template>
<script>
// 里面默认就是 vue 的语法
export default {
name: "TestPkg",
// 定义 data 并定义一个需要传递给父组件的 info 变量
data() {
return {
info: "hello 我是子组件!"
}
},
// 通过 methods 绑定一个按钮的函数
methods: {
btn(){
// 'message' 是父组件接收的子组件变量名称,this.info 也就是将数据传递给 message
this.$emit('message',this.info)
}
}
}
</script>
<style scoped>
.cc {
background: red;
}
</style>
2 编写 about.vue 父组件中代码实现接收子组件数据
<template>
<div class="about">
<h1>这是一个关于的页面</h1>
<!-- 使用 @ 绑定子组件传递过来的变量名称, @message 调用子组件中 btn() 里的 message 变量,并将数据传递给 msg 方法 -->
<TestPkg @message="msg" ></TestPkg>
<h2>{{ info }}</h2>
</div>
</template>
<script>
export default {
data(){
return {
info:""
}
},
methods: {
msg(info){ // 这里的 info 就是子组件传递过来的数据
this.info=info
console.log(info)
},
},
}
</script>
3 只要我们点击按钮,浏览器就会自动刷新并获取子组件中传递过来的数据
5 前后端数据交互:Axios
-
介绍
-
使用
-
异常处理
-
全局默认值
-
自定义实例默认值
-
拦截器
5.1 Axios 介绍
在前端页面展示的数据大多数都是通过访问一个API获取的,做这件事的方法有好几种,例如 jquery ajax、vue-resource、axios,而vue-resource是vue插件,但3版本不再更新,目前官方推荐主流的axios,aixos是一个http请求库。
官方文档: http://www.axios-js.com/zh-cn/docs/
5.2 Axios 使用
使用流程:
1、安装 axios:npm install axios
2、在 main.js 文件中全局注册
1 通过 npm 安装
root@ubuntu:~# npm install axios
2 在 main.js 全局注册,以便在其他 *.vue 文件直接使用
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
// 导入 testpkg
import TestPkg from "@/components/TestPkg";
// 1.导入 axios
import axios from "axios";
const app = createApp(App);
// 注册 2.axios
app.config.globalProperties.$axios=axios
app.use(router).mount("#app")
// createApp(App).use(router).mount("#app"); 通过上面的写法来实现该方法
// 注册 testpkg
app.component('TestPkg',TestPkg)
5.2.1 Axios 使用:GET 方法
5.2.1.1 通过触发事件获取数据
从 API 获取用户数据,在前端渲染,在这个示例中我们需要点击一个按钮触发一个事件,从而让前端渲染出对应的数据信息
1 编写 about.vue
<template>
<div class="about"></div>
<!-- 定义 button 按钮标签,并绑定 getData 事件-->
<button @click="getData">获取后端数据</button>
<h1>用户信息表</h1>
<br>
<!-- 制定表格 -->
<table border="1">
<!-- 制定表格头 -->
<thead>
<tr>
<td>ID</td>
<td>用户名</td>
<td>年龄</td>
</tr>
</thead>
<!-- 制定表格本身数据 -->
<!-- 对 data() 中的 userdata 进行遍历-->
<tbody>
<tr v-for="row in userdata" :key="row.id">
<td>{{row.id}}</td>
<td>{{row.name}}</td>
<td>{{row.age}}</td>
</tr>
</tbody>
</table>
</template>
<script>
export default {
data(){
return {
info:"",
userdata :""
}
},
// methods 中定义 getData 方法,实现与 button 中的 getData 绑定
methods:{
getData() {
// 使用 axios.get 方法,对指定 url 实现 get 方法,并将获取的数据放到 .then()
this.$axios.get("http://39.105.137.222:8089/user.json")
// response 是请求 url 成功并返回数据,然后传递给 console.log() 中将 response.data.data 输出至浏览器控制台
.then(response => {
// response.data.data 获取的就是后端 user 的数据
console.log(response.data.data),
// 将 response.data.data 赋值给 data() 中的 userdata
this.userdata = response.data.data
})
}
},
}
</script>
2 浏览器访问已经成功获取数据
5.2.1.2 打开页面就自动渲染
如果打开页面就自动渲染数据,可以放到mounted生命周期钩子
1 编写 about.vue
<template>
<div class="about"></div>
<h1>用户信息表</h1>
<br>
<!-- 制定表格 -->
<table border="1">
<!-- 制定表格头 -->
<thead>
<tr>
<td>ID</td>
<td>用户名</td>
<td>年龄</td>
</tr>
</thead>
<!-- 制定表格本身数据 -->
<!-- 对 data() 中的 userdata 进行遍历-->
<tbody>
<tr v-for="row in userdata" :key="row.id">
<td>{{row.id}}</td>
<td>{{row.name}}</td>
<td>{{row.age}}</td>
</tr>
</tbody>
</table>
</template>
<script>
export default {
data(){
return {
info:"",
userdata :""
}
},
// methods 中定义 getData 方法,与 created() 钩子实现绑定
methods:{
getData() {
// 使用 axios.get 方法,对指定 url 实现 get 方法,并将获取的数据放到 .then()
this.$axios.get("http://39.105.137.222:8089/user.json")
// response 是请求 url 成功并返回数据,然后传递给 console.log() 中将 response.data.data 输出至浏览器控制台
.then(response => {
// response.data.data 获取的就是后端 user 的数据
console.log(response.data.data),
// 将 response.data.data 赋值给 data() 中的 userdata
this.userdata = response.data.data
})
},
},
// 当浏览器打开就执行 getData() 方法,从而实现自动渲染数据
created() {
this.getData();
}
}
</script>
5.2.2 Axios 使用:POST
登录时提交表单数据案例:
这里后端可以通过 go 写一个简单的接入 API 这里我就在演示,用于登录、新增用户等场景
5.2.3 Axios 异常处理
很多时候我们可能并没有从 API 获取想要的数据。这可能是由于很多种因素引起的,比如 axios 调用可能由于多种原因而失败,包括但不限于:
- API 不工作了;
- 请求地址发错了;
- API 没有按我们预期的格式返回信息。
可以使用 catch
异常处理这些问题。
因为用户可能在访问一个 url 的时候地址写错了,从而导致如 404 的报错,但是用户又不懂那么我们可以通过异常处理给用户做一个友好的提示
1 编写 about.vue 代码
<template>
<div class="about"></div>
<!-- 定义 button 按钮标签,并绑定 getData 事件-->
<button @click="getData">获取后端数据</button>
<h1>用户信息表</h1>
<br>
<!-- 制定表格 -->
<table border="1">
<!-- 制定表格头 -->
<thead>
<tr>
<td>ID</td>
<td>用户名</td>
<td>年龄</td>
</tr>
</thead>
<!-- 制定表格本身数据 -->
<!-- 对 data() 中的 userdata 进行遍历-->
<tbody>
<tr v-for="row in userdata" :key="row.id">
<td>{{row.id}}</td>
<td>{{row.name}}</td>
<td>{{row.age}}</td>
</tr>
</tbody>
</table>
<!-- 通过 if 判断 error 是否为 true ,如果是直接输出这句话 -->
<p v-if="error" style="color: red">连接服务器失败!请稍后尝试</p>
</template>
<script>
export default {
data(){
return {
info:"",
userdata :"",
// 这里将 error 定义为 false 默认值
error : false
}
},
// methods 中定义 getData 方法,与 created() 钩子实现绑定
methods:{
getData() {
// 这里我将写入的 url 是正确的,假如 user1.json 是一个在后端不存在的地址,那么在下面的代码中通过 catch 来对起进行处理
this.$axios.get("http://39.105.137.222:8089/user.json")
.then(response => {
this.userdata = response.data.data
})
// 使用 .catch 函数,并在该函数中使用 error 方法,将 error 信息赋值给 data() 中的 error
.catch(error => { // 将响应失败的信息保存到 error 中
// 如果有 error 直接将 data() 中的 error 赋值为 true
this.error = true;
})
},
},
}
</script>
2 浏览器访问,url 正确的情况下没有报错提示
3 这里我将代码中的 url 改为 user1.json ,这是一个错误的 url
4 浏览器访问并点击获取后端请求,因为 user1.json 是一个错误的 url 直接提示错误信息
5.2.4 Axios 全局默认值
在实际开发中,几乎每个组件都会用到 axios 发起数据请求,这时候就涉及到这么一个问题,我们都知道每次请求都会涉及到地址,那么每一个 .vue 的页面都需要使用这个地址的话,就会使得我们在代码中每次都要写一次是比较繁琐的,如果每次都填写完整的请求路径,不利于后期维护因为需要每次都打开代码将其修改对应的 url 。这时可以设置全局 axios 默认值。
所谓的全局配置:
就是将域名可以全局配置到 main.js
中去指定访问的接口地址
1 编写 main.js
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
// 导入 testpkg
import TestPkg from "@/components/TestPkg";
// 1.导入 axios
import axios from "axios";
const app = createApp(App);
// 配置全局默认值,这里指定的是我个人博客地址
axios.defaults.baseURL = "http://39.105.137.222:8089/"
// 设置默认超时时间为 5s
axios.defaults.timeout = 5000
// 注册 2.axios
app.config.globalProperties.$axios=axios
app.use(router).mount("#app")
// createApp(App).use(router).mount("#app"); 通过上面的写法来实现该方法
// 注册 testpkg
app.component('TestPkg',TestPkg)
2 在 about.vue 中修改代码,这次直接不用在写地址,直接写默认的请求路径即可
<template>
<div class="about"></div>
<!-- 定义 button 按钮标签,并绑定 getData 事件-->
<button @click="getData">获取后端数据</button>
<h1>用户信息表</h1>
<br>
<!-- 制定表格 -->
<table border="1">
<!-- 制定表格头 -->
<thead>
<tr>
<td>ID</td>
<td>用户名</td>
<td>年龄</td>
</tr>
</thead>
<!-- 制定表格本身数据 -->
<!-- 对 data() 中的 userdata 进行遍历-->
<tbody>
<tr v-for="row in userdata" :key="row.id">
<td>{{row.id}}</td>
<td>{{row.name}}</td>
<td>{{row.age}}</td>
</tr>
</tbody>
</table>
</template>
<script>
export default {
data(){
return {
info:"",
userdata :"",
}
},
// methods 中定义 getData 方法,与 created() 钩子实现绑定
methods:{
getData() {
// 这里直接写需要访问的路径即可,因为默认使用了在 mian.js 中的路径
this.$axios.get("user.json")
.then(response => {
this.userdata = response.data.data
})
},
},
}
</script>
3 浏览器访问验证成功
这种全局配只支持一些基本的 url、地址 的配置,但是假如后端涉及到使用多个域名,比如在同一个 web 页面中会使用到多个 API 接口或另一个域名,那么这种方法就是不合适的
5.2.5 Axios 自定义实例默认值
有时候服务端接口有多个地址,就会涉及请求的域名不同、配置不同等,这时自定义实例可以很好解决。
1 在 src 目录中创建一个 api 目录,和一个 js 文件,如下创建一个 http.js
root@ubuntu:~# cd hello-vue/src/
root@ubuntu:~/hello-vue/src# mkdir api
root@ubuntu:~/hello-vue/src# touch api/http.js
2 在 http.js 文件中导入内容,并指定自定义实例在进行暴露
// 导入 axios 库
import axios from "axios";
// 定义 instance 实例,这是一个自定义的 url 默认值
const instance = axios.create({
baseURL:"http://39.105.137.222:8089/",
timeout: 5000
})
// 导出 instance 实例
export default instance
3 在 main.js 中将 http.js 进行注册
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import TestPkg from "@/components/TestPkg";
import axios from "axios";
// 导入 http.js 文件
import http from "./api/http";
const app = createApp(App);
// 注册 http
app.config.globalProperties.$http=http
app.config.globalProperties.$axios=axios
app.use(router).mount("#app")
app.component('TestPkg',TestPkg)
4 注册好了之后就可以在任意页面中进行使用 http,这里我对 about.vue 文件进行使用,这里我改为 $http
5 浏览器访问获取数据成功
后续就可以通过上面的方法创建多个实例来进行封装多个 *.JS 文件,每个 js 文件中有多个配置
5.2.6 Axios 拦截器
拦截器可以拦截每一次请求和响应,然后进行相应的处理。
请求拦截应用场景:
- 发起请求前添加header
响应拦截应用场景:
- 统一处理 API 响应状态码 200 或非 200 的提示消息
- 统一处理catch异常提示信息
如上图当用户发送一个 HTTP 请求给服务端并且每次都会发送 header,那么就可以使用拦截器。
或者服务端已经响应,但是需要在响应之前做一些事情,比如异常处理 catch
就可以集中的向该请求进行处理,而不再需要每次都在代码中定义 catch
,因为我们知道 catch
这里肯定是会有错误的,只要有错误就会涉及到处理,所以我们就可以将其把错误独立处理。并进行统一的配置;
因为一般请求一个数据接口,服务端都会给我们响应一个状态码,所以我们根据状态码就能判断这次请求成功与否,如不成功的话就说明获取数据失败。从而实现简化对 http 重复的使用
或者说每次前端进行请求都会携带 token ,并且 token 认证成功之后,服务端才会正确的进行响应。所以这个 token 就存放在 header 中
5.2.6.1 如何使用 Axios 拦截器
如上图:
我定义了一个浏览器和一个服务端,服务端提供 API 。
请求拦截器:
正常来说浏览器需要向服务端发送 HTTP 应请求,那么当服务端接收到请求之后就会做出对应的响应,并且会在发送请求之前会给该请求添加一些数据、或请求头
响应拦截器:
比如浏览器接收到服务端得响应,但是是一个错误的状态码,那么响应拦截器就会对其做出相应的处理。
所以请求拦截器、响应拦截器都是在 axios 请求前,或者响应之后进行处理
如上面自定义 http.js 文件,那么我们就可以基于 http.js 里面添加 Axios 请求拦截器,和响应拦截器
1 编写 http.js
// 导入 axios 库
import axios from "axios";
// 定义 instance 实例,这是一个自定义的 url 默认值
const instance = axios.create({
baseURL:"http://39.105.137.222:8089/",
timeout: 5000,
})
// 请求拦截器
// 请求成功就会使用 config.headers[] 携带请求并 return header
// 如果请求失败就会执行 error => 中的代码
instance.interceptors.request.use(config => {
// 发送所有请求都会经过这里
// 这里我添加一个请求头,并且所有的请求都会携带这个 header 发送至服务端
config.headers['testHeader'] = '12345'
return config
},
// 如果说请求错误,那么就可以通过下面的方法实现,error 用于处理请求错误
error => {
console.log("请求:",error)
return Promise.reject(error)
},
)
// 响应拦截器
instance.interceptors.response.use(response => {
// 处理响应数据,这里获取后端数据中的 code 状态码
console.log("响应:",response.data.code);
// 这里直接定义了响应错误的处理,如果不在这里编写那么我们就会在每个页面中对数据处理出错位置进行编写
if (response.data.code != 200) {
alert("请求数据返回失败!")
}
return response
}, error =>{
// 处理相应错误 (也就是 catch 操作)
console.log(111,error)
return Promise.reject(error)
}
)
// 导出 instance 实例
export default instance
2 浏览器请求,可以看到已经将我们的 testHeader
添加到了请求 header 中
3 我将代码中的请求拦截器中的 config.headers['testHeader'] = '12345'
注释,从而观察响应浏览器效果,因为如果不注释所有的用户请求都会被请求拦截器所处理从而无法获取响应信息,因为这里后端服务我使用的是 nginx,会涉及到跨域影响
4 浏览器再次请求,观察 console 已经成功输出响应拦截器中的内容
5 修改响应拦截器中的响应码,这里我特地写成 if (response.data.code != 300)
从而实现响状态码应错误,用来观察前端页面是否提示 alert
中内容
6 浏览器访问,当我们点击按钮之后就会实现弹窗
总结:
因为在项目中我们会在每个 .vue
代码中写 HTTP
请求,所以会大量的使用到 catch
,这样就会比较冗余,所以我们就可以在请求拦截器、响应拦截器中统一进行处理。
这样不管在每个前端页面中即使响应是错误的都可以通过这种方法统一的提示和处理
6 Vue 路由:Vue Router
• 介绍
• 使用
• 路由传参
• 导航守卫
6.1 介绍
Vue Router 是 Vue.js (opens new window)官方的路由管理器。它和 Vue.js 的
核心深度集成,包含的功能有:
• 嵌套的路由/视图表
• 模块化的、基于组件的路由配置
• 路由参数、查询、通配符
• 基于 Vue.js 过渡系统的视图过渡效果
• 细粒度的导航控制
6.2 Vue Router安装
在用脚手架创建项目时已经选择安装上了
如果刚开始没有,通过 npm 安装:npm install vue-router@4
安装完后会有router目录
使用流程:
-
开发页面(组件)
-
定义路由
-
组件使用路由
如上图就是现在的页面中导航是如何实现的:
App.vue 其实就是当前 hello-vue 项目的根页面,可以看到下图中在 App.vue 文件里面就有 router-view ,这个就是用来引入渲染页面的
然后在通过 router-link 导航,分别是 /about 和 / 页面中;然后在 / 中引入了 HelloWorld.vue
子组件
那么现在我们自定义一个页面,用来练习如何使用 router
6.3 使用 router 示例
1 这里我 views 目录下新建一个关于用户信息的页面,等会将该页面添加至路由中
root@ubuntu:~/hello-vue/src/views# pwd
/root/hello-vue/src/views
root@ubuntu:~/hello-vue/src/views# cat UserPage.vue
<template>
</template>
<script>
export default {
name: "UserPage"
}
</script>
<style scoped>
</style>
现在这个页面是没有在我们的当前站点中进行使用的,所以需要将这个页面添加至 router 中
2 向 UserPage 文件添加数据,这里我只是简单设置了颜色和对应的列表
<template>
<div class="cc">
<ul>
<li>姓名</li>
<li>年龄</li>
<li>性别</li>
</ul>
</div>
</template>
<script>
export default {
name: "UserPage"
}
</script>
<style scoped>
.cc {
background: wheat;
}
</style>
3 向 router/index.js
中添加路由
# 修改该文件
root@ubuntu:~/hello-vue/src/views# ll /root/hello-vue/src/router/index.js
-rw-r--r-- 1 root root 673 Sep 6 22:23 /root/hello-vue/src/router/index.js
import { createRouter, createWebHashHistory } from "vue-router";
import HomeView from "../views/HomeView.vue";
// 导入组件的方式分为两种
// 方式1.先导入,下面在引用
import UserPage from "@/views/UserPage";
// 一、定义路由对象
const routes = [
{
path: "/",
name: "home",
component: HomeView,
},
{
path: "/about",
name: "about",
// 方式2.当路由被访问时才会加载该组件(惰性方式)
component: () =>
import(/* webpackChunkName: "about" */ "../views/AboutView.vue"),
},
{
// 添加在方式1 中的 UserPage 组件为路由
path: "/user",
name: "user",
component: UserPage
},
];
// 二、创建一个路由实例,并传递上面路由对象
const router = createRouter({
history: createWebHashHistory(),
routes, // 将在 一 步骤中的路由对象传递至此
});
// 三、导出路由
export default router;
4 修改 App.vue 文件,增加新加入的组件
5 浏览器访问成功,并添加了 user URL,并且也将 h1
标签中的横杠添加在内容的上下部分
从这个示例可以看到我们点击也没上对应的按钮时并没有对后端 server 端发起请求,只是一个页面间的切换
6.4 Vue Router 路由传参(常用)
URL传参:一般用于页面跳转,将当前数据传递到新页面,例如详情页,比如从一个链接里面跳转至另一个连接中
跳转传参的 id ,一般有两种方式:
params传参
• 配置路由: {path: ‘/user/:id’, component: about}
• 传递方式:<router-link to="/user/6/"></router-link>
• 传递后路径:/user/6
• 接收参数:$route.params.id
query传参
• 配置路由: {path: ‘/user/’, component: about}
• 传递方式:<router-link to=”{path: ‘/about ‘, query:{id:6}}”></router-link>
• 传递后路径:/user?id=6
• 接收参数:$route.query.id
6.4.1 通过路由实现跳转
这里我依旧对 UserPage 页面做修改,我在该文件中添加对应的超链接,比如做一个按钮,点击之后就可以跳转到用的详情页面
1 修改 UserPage 文件
<template>
<div class="cc">
<ul>
<li>
<!-- 这里我对姓名做一个路由跳转至 /name 页面中 -->
<router-link to="/name">姓名</router-link>
</li>
<li>年龄</li>
<li>性别</li>
</ul>
</div>
</template>
<script>
export default {
name: "UserPage"
}
</script>
<style scoped>
.cc {
background: wheat;
}
</style>
2 创建 Name.vue 文件,该文件用来实现在用户页面点击姓名时实现跳转
root@ubuntu:~/hello-vue/src/views# ll Name.vue
3 编写 Name.vue 文件
<template>
<!-- 定义 h1 标签内容为 这是用户姓名页面 -->
<h1>这是用户姓名页面</h1>
</template>
<script>
export default {
name: "Name"
}
</script>
<style scoped>
</style>
4 修改 router/index.js
文件,添加路由
import { createRouter, createWebHashHistory } from "vue-router";
import HomeView from "../views/HomeView.vue";
import UserPage from "@/views/UserPage";
// 导入 Name 组件并指定文件
import Name from "@/views/Name"
// 一、定义路由对象
const routes = [
{
path: "/",
name: "home",
component: HomeView,
},
{
path: "/about",
name: "about",
component: () =>
import(/* webpackChunkName: "about" */ "../views/AboutView.vue"),
},
{
path: "/user",
name: "user",
component: UserPage
},
// 添加 UserPage 组件为路由
{
path: "/name",
name: "name",
component: Name
},
];
// 二、创建一个路由实例,并传递上面路由对象
const router = createRouter({
history: createWebHashHistory(),
routes, // 将在 一 步骤中的路由对象传递至此
});
// 三、导出路由
export default router;
6 浏览器访问点击姓名
跳转至 http://10.0.0.134:8080/#/name 的 url,内容和我们在 Name.vue 中的内容一样
正常来说该页面需要向服务器端请求对应的接口,如 http://10.0.0.134:8080/#/name/1 这样的 url,然后服务端会更加这个 uid=1 同时查询数据库,并返回详情最后渲染在 web 页面上
6.5 Vue Router 导航守卫
正如其名,vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。简单来说,就是在路由跳转时候的一些钩子,当从一个页面跳转到另一个页面时,可以在跳转前、中、后做一些事情(也就是在跳转的时候我们需要处理什么事件,比如什么时候才能够跳转;类似于一个访问控制)
可以使用 router.beforeEach
注册一个全局前置守卫
当一个导航触发时,就会异步执行这个回调函数。
每个守卫方法接收参数:
• to:即将要跳转的目标,是一个路由对象
• from:当前导航正要离开的路由,也是一个路由对象
• next:可选,是一个方法,直接跳转到对应的下一个目标
可以返回的值如下:
• false:取消当前的导航。如果浏览器的 URL 改变了(可能
是用户手动或者浏览器后退按钮),那么 URL 地址会重置
到 from 路由对应的地址。
• 一个路由地址:通过一个路由地址跳转到一个不同的地址。
6.5.1 Vue Router 导航守卫示例
1 修改 index.js
文件,并将守护方法获取的数据输出值 console.log
中
2 浏览器访问,这里我点击姓名
可以在 console 中看到对应的守护获取信息,如跳转到那个路径等信息
这样就可以基于守卫获取的数据进行拦截,而我们只需要在 router.beforeEach()
方法中编写对应的拦截处理动作
使用场景:
比如在我们在使用 token 与后端进行交互认证,认证成功之后服务端才会返回请求数据。那么我们就可以使用导航守卫,用来判断本地是否拥有该 token ,如果本地有这个 token 的话才会进行跳转访问其他前端页面。如果没有 token 的话就直接跳转回登录页面
如下示例
6.5.2 导航守卫实现访问控制示例
1 编写 index.js 文件
import { createRouter, createWebHashHistory } from "vue-router";
import HomeView from "../views/HomeView.vue";
import UserPage from "@/views/UserPage";
// 导入 Name 组件并指定文件
import Name from "@/views/Name"
// 一、定义路由对象
const routes = [
{
path: "/",
name: "home",
component: HomeView,
},
{
path: "/about",
name: "about",
component: () =>
import(/* webpackChunkName: "about" */ "../views/AboutView.vue"),
},
{
path: "/user",
name: "user",
component: UserPage
},
// 添加 UserPage 组件为路由
{
path: "/name",
name: "name",
component: Name
},
];
// 二、创建一个路由实例,并传递上面路由对象
const router = createRouter({
history: createWebHashHistory(),
routes, // 将在 一 步骤中的路由对象传递至此
});
// 注册全局前置守卫
router.beforeEach((to,from,next) => {
// 跳转前拦截处理
console.log(to,from)
// 如果访问的页面为 /login 那么就直接放行
if (to.path == '/login') {
// next() 如果当用户访问 /login 就正常跳转
return next();
}
const token = '666'; // 通常基于本地 session 中进行获取,而我这里只是用于模拟 token = 666
// 如果用户有 token 那么就正常跳转访问
if (token) {
next()
}else {
// 如果用户没有 token 那么就跳转 /login 页面
return next("/login")
}
});
// 三、导出路由
export default router;
注意:在上面的代码中我们给 token 定义了 666 是有值的
浏览器正常渲染内容
这里我将 index.js 中的 token="666"
改为 token=""
,也就是现在 token 是没有任何值
再次通过浏览器访问,可以看到浏览器无法正常渲染,并指定跳转至 login 页面
总结:
从而可以利用导航守卫来实现访问控制