├── build # 构建打包相关
├── mock # 项目mock 模拟数据
├── public # 静态资源
│ │── favicon.ico # favicon图标
│ └── index.html # html模板
├── src # 源代码
│ ├── api # 所有请求
│ ├── assets # 主题 字体等静态资源
│ ├── components # 全局公用组件
│ ├── icons # 项目所有 svg icons
│ ├── layout # 全局 layout
│ ├── router # 路由
│ ├── store # 全局 store管理
│ ├── styles # 全局样式
│ ├── utils # 全局公用方法
│ ├── vendor # 公用vendor
│ ├── views # views 所有页面
│ ├── App.vue # 入口页面
│ ├── main.js # 入口文件 加载组件 初始化等
│ └── permission.js # 权限管理
│ └── settings.js # 配置文件
├── tests # 测试
├── .env.xxx # 环境变量配置
├── .eslintrc.js # eslint 配置项
├── .babelrc # babel-loader 配置
├── .travis.yml # 自动化CI配置
├── vue.config.js # vue-cli 配置
├── postcss.config.js # postcss 配置
└── package.json # package.json
vue项目开始阶段
主题框架
api/books.js
utils/request.js
main.js
校验
<script>
import {
validMobile } from '@/utils/validate'
// 导入 使用全局actions
import {
mapActions } from 'vuex'
export default {
name: 'Login',
data() {
const chcekMobile = (rule, value, callback) => {
if (!validMobile(value)) {
callback(new Error('输入错误'))
} else {
callback()
}
}
return {
loginForm: {
mobile: '13800000003',
password: '123456'
},
loginRules: {
mobile: [
{
required: true, message: '输入手机号', trigger: ['blur', 'change'] },
// 自定义校验手机号
{
validator: chcekMobile, trigger: ['blur', 'change'] }
],
password: [
{
required: true, message: '输入密码', trigger: ['blur', 'change'] },
{
min: 6, max: 16, message: '输入6到16位的密码', trigger: ['blur', 'change'] }
] },
loading: false,
passwordType: 'password',
redirect: undefined
}
},
watch: {
$route: {
handler: function(route) {
this.redirect = route.query && route.query.redirect
},
immediate: true
}
},
methods: {
// user组件 ,login异步函数名
...mapActions('user', ['login']),
showPwd() {
if (this.passwordType === 'password') {
this.passwordType = ''
} else {
this.passwordType = 'password'
}
this.$nextTick(() => {
this.$refs.password.focus()
})
},
handleLogin() {
// console.log('登录')
this.$refs.loginForm.validate(async(valid) => {
if (!valid) return
this.loading = true
// 利用mapActions导入数据--->this.loginForm
await this.login(this.loginForm)
this.loading = false
this.$router.push('/')
})
}
}
}
</script>
配置跨域代理文件
1.api/user.js
封装请求
// 导入进来 request 相当于axios
import request from '@/utils/request'
// axios 封装
export function reqLogin(data) {
return request({
method: 'post',
// url: 'http://localhost:8888/api/sys/login',
url: '/sys/login',
// 和request.js---> baseURL: process.env.VUE_APP_BASE_API,
// process.env.VUE_APP_BASE_API === '/api'
data
})
}
1.
// before: requi`re('./mock/mock-server.js')
// 配置代理
proxy: {
// 请求时的路径中包含/api 就会走代理服务器 (可以显示多个)
// 自己写的路径不跨域http://localhost:8888/api/sys/login
// 真实的接口路径http://www.jd.com/api/sys/login
// 自己写的路径不跨域http://localhost:8888/api/sys/login
// 真实的接口路径http://www.jd.com/sys/login
// http://localhost:8888/api/sys/login
// =>http://www.jd.com/api/sys/login
// =>http://www.jd.com/sys/login
// 发现/api 后 将显示的前面地址替换为 target: 'http:/ww/jd.com'
/* '/api': {
// target目标:真实接口服务器地址
target: 'http:/ww/jd.com',
// pathRewrite:路径重写
pathRewrite: {
'^/api': ''// 没有/api重新配置
}
} */
// http://ihrm-java.itheima.net/api/sys/login
'/api': {
target: 'http://ihrm-java.itheima.net'
}
}
vueX管理token(持久化)
vuex 管理 token
目标
封装获取token的登录action, 在vuex中存储token
tips: 之前, 我们是在页面中发送登录请求, 获取到token后, 通过提交mutation的方式, 将token存到 vuex 中
这里希望将登录获取token
的异步操作, 也封装成 action, 封装到 vuex 中, 集中管理关于token操作
1 store/modules/user.js
准备状态
2 store/modules/user.js
封装 action 和 对应的 mutation
// 怎么axios 导入
import {
reqLogin } from '@/api/user'
import {
getToken, setToken } from '@/utils/auth.js'
const state = {
token: getToken() || ''// 初始值
}
const mutations = {
// 修改数据
// payload载荷
setToken(state, newToken) {
state.token = newToken
// cookie存token 永久存储
setToken(newToken)
}
}
const actions = {
// 发起异步请求
// 发axios---组件触发
// 登录获取token
async login(context, data) {
const res = await reqLogin(data)
// console.log(res)
// actions(login)异步数据发送--->利用 commit调用 mutations(setToken)修改属性重新赋值
context.commit('setToken', res.data)
// return res
}
}
const getters = {
}
export default ({
// 命名空间
namespaced: true,
state,
mutations,
actions,
getters
})
3 页面中导入, 调用
/ / 响应拦截器
响应拦截器统一处理失败
成功正确响应, 肯定是正常走我们的逻辑,
但是如果失败出错, 那应该要给用户提示
, 且后续代码不能接着走 .then 了, 应该走 .catch
整个系统接口有个特征, 如果是请求操作有误, 都会在响应中标记 success 为false,
所以一旦 success 为 false 了, 就需要提示错误, 并将错误 reject 抛出
import axios from 'axios'
import {
Message } from 'element-ui'
// create an axios instance
// process.env当前进程的环境变量
const service = axios.create({
// 设置请求根路径
baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
// withCredentials: true, // send cookies when cross-domain requests
timeout: 5000 // request timeout
})
/* // 创建了axios实例, 使用的是自己的配置项
const instance = axios.create({
// 开发环境, 找 env.development, 找 VUE_APP_BASE_API 变量
// 生产环境, 找 env.production, 找 VUE_APP_BASE_API 变量
baseURL: process.env.VUE_APP_BASE_API, // 环境变量
timeout: 5000 // request timeout
})
// 请求拦截器
// 响应拦截器 */
// 响应拦截器
service.interceptors.response.use((response) => {
// 将axios放回数据解了一层壳
const res = response.data
const {
message, success } = res
if (!success) {
Message.error(message)
return Promise.reject(new Error(message))
}
return res
}, (error) => {
// 处理 400 401 500错误
Message.error(error.message)
return Promise.reject(error)
})
export default service
promise
**// promise承诺, 一般承诺的是将来的事情, 有成功, 有失败
// promise的三个状态
// pending 等待中..
// fulfilled 成功
// rejected 失败
const p = new Promise((resolve, reject) => {
// promise 内部可以封装一个异步的操作
// resolve 在成功的时候调用的函数 将promise的状态, 改成了fulfilled
// reject 在失败的时候调用的函数 将promise的状态, 改成了rejected
})
**