目标: 设置统一的本地访问端口和网站title
本节注意
: 修改服务的配置文件,想要生效的话,必须要重新启动服务,值‘8888’后面不能留有空格
vue.config.js
**中进行设置vue.config.js
就是vue项目相关的编译,配置,打包,启动服务相关的配置文件,它的核心在于webpack,但是又不同于webpack,相当于改良版的webpack const port = process.env.port || process.env.npm_config_port || 9528
我们看到上面的 **`process.env.port`**
实际上是一个nodejs服务下的环境变量,该变量在哪里设置呢?
在项目下, 我们发现了**.env.development
和.env.production
**两个文件
development => 开发环境
production => 生产环境
当我们运行npm run dev进行开发调试的时候,此时会加载执行**.env.development
**文件内容
当我们运行npm run build:prod进行生产环境打包的时候,会加载执行**.env.production
**文件内容
所以,如果想要设置开发环境的接口,直接在**.env.development
**中写入对于port变量的赋值即可
# 设置端口号
port = 8888 // 因为是开发使用的端口号, 所以不需要在production里面写
settings.js
**文件人力资源管理平台
"module.exports = {
title: '人力资源管理平台', // 项目名称, 也就是顶部的网页名称
/**
* @type {boolean} true | false
* @description Whether fix the header
*/
fixedHeader: false, // 固定头部
/**
* @type {boolean} true | false
* @description Whether show the logo in sidebar
*/
sidebarLogo: false // 显示左侧菜单logo
}
**目标
**完成登录页面的基础布局
~
**符号,否则不识别目标:对登录表单进行规则校验
本节注意: 修饰符(native)的使用
data() {
// 自定义校验函数
const validateMobile = function(rule, value, callback) {
// 校验value
// if (validMobile(value)) {
// // 如果通过 直接执行callback
// callback()
// } else {
// callback(new Error('手机号格式不正确'))
// }
validMobile(value) ? callback() : callback(new Error('手机号格式不正确'))
}
return {
loginForm: {
mobile: '13800000002',
password: '123456'
},
loginRules: {
mobile: [{
required: true, trigger: 'blur', message: '手机号不能为空' }, {
validator: validateMobile, trigger: 'blur'
}],
password: [{
required: true, trigger: 'blur', message: '密码不能为空' }, {
min: 6, max: 16, message: '密码的长度在6-16位之间 ', trigger: 'blur'
}]
},
loading: false,
passwordType: 'password',
redirect: undefined
}
},
utils/validate.js
**方法中增加了一个校验手机号的方法utils/validate.js
**是一个专门存放校验工具方法的文件/**
* 校验手机号
* **/
export function validMobile(str) {
return /^1[3-9]\d{9}$/.test(str) // 校验手机号
}
@keyup.enter.native
和 @click.native.prevent
enter
**属于按键修饰符,如果我们想监听在按回车键的时候触发,可以如下编写native
表示监听组件的原生事件,比如 keyup就是于input的原生事件,这里写native表示keyup是一个原生事件目标
: 通过配置vue-cli的代理解决跨域访问的问题
前后分离
项目,也就是前端项目
和后端接口
并不在一个域名之下,那么前端项目访问后端接口必然存在跨域
**的行为.请注意
,我们所遇到的这种跨域是位于开发环境的,真正部署上线时的跨域是生产环境的本节注意
:我们并没有进行**pathRewrite
**,
ihrm-java.itheima.net/api
**这种格式,所以不需要重写vue.config.js
**的改动如果要生效,需要进行重启服务开发环境的跨域,也就是在vue-cli脚手架环境
下开发启动服务时,我们访问接口所遇到的跨域问题,vue-cli为我们在本地开启了一个服务
,可以通过这个服务帮我们代理请求
**,解决跨域问题。
这就是vue-cli配置 webpack 的反向代理
vue.config.js
**,这里有我们需要的 代理选项module.exports = {
devServer: {
// 代理配置
proxy: {
// 这里的api 表示如果我们的请求地址有/api的时候,就出触发代理机制
// localhost:8888/api/abc => 代理给另一个服务器
// 本地的前端 =》 本地的后端 =》 代理我们向另一个服务器发请求 (行得通)
// 本地的前端 =》 另外一个服务器发请求 (跨域 行不通)
'/api': {
target: 'www.baidu.com', // 我们要代理的地址
changeOrigin: true, // 是否跨域 需要设置此值为true 才可以让本地服务代理我们发出请求
// 路径重写
pathRewrite: {
// 重新路由 localhost:8888/api/login => www.baidu.com/api/login
'^/api': '' // 假设我们想把 localhost:8888/api/login 变成www.baidu.com/login 就需要这么做
}
},
}
}
}
以上就是我们在vue-cli项目中配置的代理设置
// 代理跨域的配置 注意 要在 devServer: 里面写
proxy: {
// 当我们的本地的请求 有/api的时候,就会代理我们的请求地址向另外一个服务器发出请求
'/api': {
target: 'http://ihrm-java.itheima.net/', // 跨域请求的地址
changeOrigin: true // 只有这个值为true的情况下 才表示开启跨域
}
}
// before: require('./mock/mock-server.js'), // 注释mock-server加载
生产环境表示我们已经开发完成项目,将项目部署到了服务器上,这时已经没有了vue-cli脚手架的**辅助
了,我们只是把打包好的html+js+css
交付运维人员,放到Nginx
服务器而已,所以此时需要借助Nginx
**的反向代理来进行
server{
# 监听9099端口
listen 9099;
# 本地的域名是localhost
server_name localhost;
#凡是localhost:9099/api这个样子的,都转发到真正的服务端地址http://baidu.com
location ^~ /api {
proxy_pass http://baidu.com;
}
}
注意: 这里的操作一般由运维人员完成,需要前端进行操作,这里我们进行一下简单了解
更多正向代理和反向代理知识,请阅读这篇文章Nginx反向代理
目标:` 在单独请求模块中,单独封装登录接口
基础模板已经有了原来的登录代码,我们只需要进行简单的改造即可
export function login(data) {
// 返回一个axios对象 => promise // 返回了一个promise对象
return request({
url: '/sys/login', // 因为所有的接口都要跨域 表示所有的接口要带 /api
method: 'post',
data
})
}
目标:
**在vuex中封装登录的action,并处理token本节任务
:封装Vuex的登录Action并处理token钥匙
**,我们需要让vuex来介入,将用户的token状态共享,更方便的读取,1. 实现store/modules/user.js基本配置
// 状态
const state = {
}
// 修改状态
const mutations = {
}
// 执行异步
const actions = {
}
export default {
namespaced: true,
state,
mutations,
actions
}
2. 设置token的共享状态
const state = {
token: null
}
我们需要知道,**
钥匙
**不能每次都通过登录获取,我们可以将token放置到本地的缓存中
在**utils/auth.js
中,基础模板已经为我们提供了获取token
,设置token
,删除token
**的方法,可以直接使用
3. 只需要将存储的key放置成特定值即可
import Cookies from 'js-cookie'
const TokenKey = 'hrsaas-ihrm-token' // 设定一个独一无二的key
export function getToken() {
return Cookies.get(TokenKey)
}
export function setToken(token) {
return Cookies.set(TokenKey, token)
}
export function removeToken() {
return Cookies.remove(TokenKey)
}
4. 初始化token状态 - store/modules/user.js
import {
getToken, setToken, removeToken } from '@/utils/auth'
// 状态
// 初始化的时候从缓存中读取状态 并赋值到初始化的状态上
// Vuex的持久化 如何实现 ? Vuex和前端缓存相结合
const state = {
token: getToken() // 设置token初始状态 token持久化 => 放到缓存中
}
5. 提供修改token的mutations
// 修改状态
const mutations = {
// 设置token
setToken(state, token) {
state.token = token // 设置token 只是修改state的数据 123 =》 1234
// vuex变化 => 缓存数据
setToken(token) // vuex和 缓存数据的同步
},
// 删除缓存
removeToken(state) {
state.token = null // 删除vuex的token
removeToken() // 先清除 vuex 再清除缓存 vuex和 缓存数据的同步
}
}
6. 封装登录的Action
登录action要做的事情,调用登录接口
,成功后设置token到vuex
,失败则返回失败
async/await
**语法// 执行异步
const actions = {
// 定义login action 也需要参数 调用action时 传递过来的参数
async login(context, data) {
const result = await login(data) // 实际上就是一个promise result就是执行的结果
// axios默认给数据加了一层data
if (result.data.success) {
// 表示登录接口调用成功 也就是意味着你的用户名和密码是正确的
// 现在有用户token
// actions 修改state 必须通过mutations
context.commit('setToken', result.data.data)
}
}
}
then
**语法 // 为什么async/await 不用返回new Promise,因为 async函数本身就是 Promise,promise的值返回的值
login(context, data) {
return new Promise(function(resolve) {
login(data).then(result => {
if (result.data.success) {
context.commit('setToken', result.data.data) // 提交mutations设置token
resolve() // 表示执行成功了
}
})
})
}
7. 除此之外,为了更好的让其他模块和组件更好的获取token数据,我们可以在store/getters.js
中将token值作为公共的访问属性放出
const getters = {
sidebar: state => state.app.sidebar,
device: state => state.app.device,
token: state => state.user.token // 在根级的getters上 开发子模块的属性给别人看 给别人用
}
export default getters
目标
**设置request环境变量和异常处理本节注意
:我们这里生产环境和开发环境设置了不同的值,后续我们还会在生产环境部署的时候,去配置该值所对应的反向代理,反向代理指向哪个地址,完全由我们自己决定,不会和开发环境冲突前端主要区分两个环境,开发环境
,生产环境
也就是两个环境发出的请求地址是不同的,用什么区分呢?
$ process.env.NODE_ENV
# 当他的值为production时为生产环境 为development时为开发环境
.env.development
和.env.production
定义变量,变量自动就为当前环境的值VUE_APP_BASE_API
,该变量可以作为axios请求的baseURL
**/dev-api
和/prod-api
**/api
**,所以可以统一下.env.development
** 开发环境中的 地址# 开发环境的基础地址和代理对应
VUE_APP_BASE_API = '/api'
这个是 生产环境的
# 这里配置了/api,意味着需要在Nginx服务器上为该服务配置 nginx的反向代理对应/prod-api的地址
VUE_APP_BASE_API = '/prod-api'
const service = axios.create({
// 如果执行 npm run dev 值为 /api 正确 /api 这个代理只是给开发环境配置的代理
// 如果执行 npm run build 值为 /prod-api 没关系 运维应该在上线的时候 给你配置上 /prod-api的代理
baseURL: process.env.VUE_APP_BASE_API, // 设置axios请求的基础的基础地址
timeout: 5000 // 定义5秒超时
}) // 创建一个axios的实例
data的包裹
**,我们需要在这里处理下success
为false
**,并没有reject,我们需要一并处理下// 响应拦截器
service.interceptors.response.use(response => {
// axios默认加了一层data
const {
success, message, data } = response.data
// 要根据success的成功与否决定下面的操作
if (success) {
return data
} else {
// 业务已经错误了 还能进then ? 不能 ! 应该进catch
Message.error(message) // 提示错误消息
return Promise.reject(new Error(message))
}
}, error => {
Message.error(error.message) // 提示错误信息
return Promise.reject(error) // 返回执行错误 让当前的执行链跳出成功 直接进入 catch
})
async login(context, data) {
// 经过响应拦截器的处理之后 这里的result实际上就是 token
const result = await login(data) // 实际上就是一个promise result就是执行的结果
// axios默认给数据加了一层data
// 表示登录接口调用成功 也就是意味着你的用户名和密码是正确的
// 现在有用户token
// actions 修改state 必须通过mutations
context.commit('setToken', result)
}
本节任务`: 完成request环境变量和异常的处理
目标
调用vuex中的登录action,并跳转到主页本节注意
:我们调用的是Vuex中子模块的action,该模块我们进行了namespaced: true,所以引用aciton时需要带上**user/
**, 并且在使用该方法时,直接使用 this['user/login']
, 使用this.user/login 语法是错误的本节任务
:登录页面调用登录action,处理异常
import {
mapActions } from 'vuex' // 引入vuex的辅助函数
methods: {
...mapActions(['user/login'])
}
this.$refs.loginForm.validate(async isOK => {
if (isOK) {
try {
this.loading = true
// 只有校验通过了 我们才去调用action
await this['user/login'](this.loginForm)
// 应该登录成功之后
// async标记的函数实际上一个promise对象
// await下面的代码 都是成功执行的代码
this.$router.push('/')
} catch (error) {
console.log(error)
} finally {
// 不论执行try 还是catch 都去关闭转圈
this.loading = false
}
}
})