> 文档中心 > Vue和Vue-Element-Admin(十一):axios,mockjs和vuex

Vue和Vue-Element-Admin(十一):axios,mockjs和vuex

axios,mockjs和vuex在开发/生产环境基本是耦合的,axios完成请求发送/接收及封装,mockjs进行数据的拦截/模拟,vuex进行本地数据存储及全局变量维护。
以登录场景为例,登录表单el-form标签绑定form.item数据,el-input分别对应item.username和item.passwd,点击登录的button触发login()方法,入参即item数据,login()方法使用被axios统一封装的request(增加baseurl,请求头等)发起http请求,mockjs拦截请求返回模拟数据,axios拿到返回后封装respond(增加或修改相应code,处理权限等),vuex存储模拟的token,其他components比如router可以直接引用token来判断是否有权限跳转。
实现如下的居中登录输入框,登录触发login请求,图中/api/menu/getMenu的url就是login方法
在这里插入图片描述
form表单对应的username和password接收参数:

<template>  <el-form    :model="form"    status-icon    :rules="rules"    ref="form"    label-width="100px"    class="login-container"  >    <h3 class="login_title">系统登陆</h3>    <el-form-item      label="用户名"      label-width="80px"      prop="username"      class="username"    >      <el-input type="input" v-model="form.username" auto-complete="off" placeholder="请输入账号"      ></el-input>    </el-form-item>    <el-form-item label="密码" label-width="80px" prop="password">      <el-input type="password" v-model="form.password" auto-complete="off" placeholder="请输入密码"      ></el-input>    </el-form-item>    <el-form-item class="login_submit">      <el-button type="primary" @click="login" class="login_submit" >登陆</el-button      >    </el-form-item>  </el-form></template><script>// import Mock from 'mockjs'import { getMenu } from '../../api/menuRequest'export default {  name: 'login',  data() {    return {      form: {},      rules: { username: [   { required: true, message: '请输入用户名', trigger: 'blur' },   {     min: 3,     message: '用户名长度不能小于3位',     trigger: 'blur'   } ], password: [   {     required: true,     message: '请输入密码',     trigger: 'blur'   } ]      }    }  },  methods: {    login() {      getMenu(this.form).then(({ data: res }) => { console.log(res, 'res') if (res.code == 20000) {   this.$store.commit('clearMenu')   this.$store.commit('setMenu', res.menu)   this.$store.commit('setToken', res.token)   this.$store.commit('addMenu', this.$router)   this.$router.push({ name: 'main' }) } else {   this.$message.warning(res.data.message) }      })    }  }}</script><style lang="less" scoped>.login-container {  border-radius: 15px;  background-clip: padding-box;  //margin: 180px auto;  position: absolute;  width: 350px;  padding: 35px 35px 15px 35px;  background-color: #fff;  border: 1px solid #eaeaea;  box-shadow: 0 0 25px #cac6c6;  left: 50%;  top: 50%;  transform: translate(-60%, -60%);}.login_title {  margin: 0px auto 40px auto;  text-align: center;  color: #505458;}.login_submit {  margin: 10px auto 0 auto;}</style>

axios

引入axios

main.js中

import http from 'axios'Vue.prototype.$http = http

封装request和response

axios中文文档
使用axios.create([config])自定义配置新建一个 axios 实例service ,拦截器在文档中这样描述:

// 添加请求拦截器axios.interceptors.request.use(function (config) {    // 在发送请求之前做些什么    return config;  }, function (error) {    // 对请求错误做些什么    return Promise.reject(error);  });// 添加响应拦截器axios.interceptors.response.use(function (response) {    // 对响应数据做点什么    return response;  }, function (error) {    // 对响应错误做点什么    return Promise.reject(error);  });

这里发起请求时候添加messagebox和store判断是否有token,没有提醒,拿到响应后如果是20000那么说明响应ok,但是如果是50008和其他code,说明token过期了,你要重新登录。

import axios from 'axios'import { MessageBox, Message } from 'element-ui'import store from '../store'const service = axios.create({  baseURL: '',  timeout: 5000 // request timeout})service.interceptors.request.use(config => {  // do something before request is sent  if (store.getters.token) {    config.headers = {      URL: this.baseURL    }  }  return config})// response interceptorservice.interceptors.response.use(  response => {    const res = response.data    if (res.code !== 20000) {      Message({ message: res.message || 'Error', type: 'error', duration: 5 * 1000      })      // 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;      if (res.code === 50008 || res.code === 50012 || res.code === 50014) { MessageBox.confirm(   'You have been logged out, you can cancel to stay on this page, or log in again',   'Confirm logout',   {     confirmButtonText: 'Re-Login',     cancelButtonText: 'Cancel',     type: 'warning'   } ).then(() => {   store.dispatch('user/resetToken').then(() => {     location.reload()   }) })      }      return Promise.reject(new Error(res.message || 'Error'))    } else {      return res    }  },  error => {    console.log('err' + error) // for debug    Message({      message: error.message,      type: 'error',      duration: 5 * 1000    })    return Promise.reject(error)  })export default service

定义login接口

有统一axios模块,只需要实例化request就是api接口,那么这个request就有url,method,data三个参数,其中data和param分别是body和路径传参。

import request from './request'export function getMenu(param) {  return request({    url: '/api/menu/getMenu',    method: 'post',    data: param  })}

mockjs

mockjs,mockjs是如何自动拦截请求的,答案是url路径,路径指的是baseurl+request.url拼接后的全路径,普通的vue项目在根目录的config目录中有dev.env.js和prod.env.js,dev增加MOCK为ture:

'use strict'const merge = require('webpack-merge')const prodEnv = require('./prod.env')module.exports = merge(prodEnv, {  NODE_ENV: '"development"',  MOCK: true,  BASE_URL: 'http://127.0.0.1:9999/'})

在main.js中增加动态判断引入:

// 根据config下的配置文件类型,判断是否使用mock数据process.env.MOCK && require('../src/mock/index')

/src/mock/index.js文件如下:

import Mock from 'mockjs'import menuApi from './mockData/menuApi'Mock.mock('/api/menu/getMenu', menuApi.getMenu)// mock拦截按照完整路径匹配,这里正则表达式拦截带参数的get请求

vuex

vuex就是用来全局引用的,但是main.js中不需要挂载,直接在store目录先新建index.js,如下把同级modules中的所有需要存储到vuex中都引入:

import Vue from 'vue'import Vuex from 'vuex'Vue.use(Vuex)const modulesFiles = require.context('./modules', true, /\.js$/)const modules = modulesFiles.keys().reduce((modules, modulePath) => {  // set './app.js' => 'app'  const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')  const value = modulesFiles(modulePath)  modules[moduleName] = value.default  return modules}, {})const store = new Vuex.Store({  modules})export default store

每个需要维护的一类状态包括state和mutation,mutation被调用来修改state:

import Cookies from 'js-cookie'export default {  state: {    token: ''  },  mutations: {    setToken(state, val) {      state.token = val      Cookies.set('token', val)    },    clearToken(state) {      state.token = ''      Cookies.remove('token')    },    getToken(state) {      state.token = state.token || Cookies.get('token')    }  }}