初始化vuecli项目
vue create my-app
cd my-app
yarn add -D less-loader@7.x less
yarn add element-ui vuex axios nprogress mockjs
vue add router
引入axios
src\util\util.js
/**
* 表单序列化
* @param {Object} data 请求参数
*/
export const serialize = data => {
const list = []
Object.keys(data).forEach(ele => {
list.push(`${ele}=${data[ele]}`)
})
return list.join('&')
}
src\api\axios.js
import axios from 'axios'
import qs from 'qs'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import { Message } from 'element-ui'
import { serialize } from '@/util/util'
const { NODE_ENV } = process.env
if (NODE_ENV === 'production') {
axios.defaults.baseURL = window.location.origin
}
// axios.defaults.timeout = 30000
// 返回其他状态吗
axios.defaults.validateStatus = function(status) {
return status >= 200 && status <= 500 // 默认的
}
// 跨域请求,允许保存cookie
axios.defaults.withCredentials = true
NProgress.configure({
showSpinner: false
})
/**
* HTTPrequest拦截
*/
axios.interceptors.request.use(config => {
NProgress.start() // start progress bar
const { method, headers } = config
const isToken = (config.headers || {}).isToken === false
// 获取存储的token,若接口需要登录权限,则加上headers
//const token = null
//if (token && !isToken) {
//config.headers.Authorization = 'Bearer ' + token // token
//}
// headers中配置serialize为true开启序列化
if (method === 'post' && headers.serialize) {
config.data = serialize(config.data)
delete config.data.serialize
}
if (method === 'get') {
config.paramsSerializer = function(params) {
return qs.stringify(params, { arrayFormat: 'repeat' })
}
}
return config
}, error => {
return Promise.reject(error)
})
/**
* HTTPresponse拦截
*/
axios.interceptors.response.use(res => {
NProgress.done()
const {
data = {},
status,
statusText
} = res
var message = data.message || `${status} ${statusText}` || '未知错误'
if (status !== 200) {
Message.error(message)
return Promise.reject(new Error(message))
}
const { code = 200 } = data
if (code !== 200) {
if (code === 401) {
// 跳转到登录页面
}
Message.error(message)
return Promise.reject(new Error(message))
}
return Promise.resolve(data.data)
}, err => {
NProgress.done()
Message.error(err)
return Promise.reject(err)
})
export default axios
编写mock
mock\utils.js
/**
* @param {string} url
* @returns {Object}
*/
function param2Obj(url) {
const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ')
if (!search) {
return {}
}
const obj = {}
const searchArr = search.split('&')
searchArr.forEach(v => {
const index = v.indexOf('=')
if (index !== -1) {
const name = v.substring(0, index)
const val = v.substring(index + 1, v.length)
obj[name] = val
}
})
return obj
}
/**
* This is just a simple version of deep copy
* Has a lot of edge cases bug
* If you want to use a perfect deep copy, use lodash's _.cloneDeep
* @param {Object} source
* @returns {Object}
*/
function deepClone(source) {
if (!source && typeof source !== 'object') {
throw new Error('error arguments', 'deepClone')
}
const targetObj = source.constructor === Array ? [] : {}
Object.keys(source).forEach(keys => {
if (source[keys] && typeof source[keys] === 'object') {
targetObj[keys] = deepClone(source[keys])
} else {
targetObj[keys] = source[keys]
}
})
return targetObj
}
/**
* 统一api返回结果
*/
class Respones {
constructor(code = 200, message = null, data = null) {
this.code = code // 状态码 200: 成功 401: 未登录
this.message = message // 提示信息
this.data = data // 返回结果
// this.success = code === 200
}
static ok(data = null, message = null) {
return new Respones(undefined, message, data)
}
static failed(message = '未知错误', data = null) {
return new Respones(500, message, data)
}
}
/**
* 生成从min到max的随机整数
* @param {Number} min 最小值
* @param {Number} max 最大值
*/
function randomNum(min = 0, max = 100) {
return Math.floor(Math.random() * (max - min + 1) + min)
}
module.exports = {
param2Obj,
deepClone,
randomNum,
Respones
}
mock\Login.js
const { Respones } = require('./utils')
module.exports = [
{
url: '/api/Login/Login\.*',
type: 'get',
response: () => {
// const { query, params, body, headers } = config
// const { cookie } = headers
// console.log(query, params, body, cookie)
return Respones.ok('登录成功')
}
},
{
url: '/api/Login/Logout\.*',
type: 'get',
response: () => {
return Respones.ok('退出成功')
}
}
]
mock\entity\User.js
module.exports = {
id: '@integer(1,10000000000000000000)',
name: '@last()',
pwd: '@string',
realname: '@cname()',
role: '@pick([0,1,100])',
token: '@string'
}
mock\User.js
const { Respones, randomNum } = require('./utils')
const user = require('./entity/User')
module.exports = [
{
url: '/api/User/GetCurrentUser',
type: 'get',
response: () => {
return Respones.ok({ user }.user)
}
},
{
url: '/api/User/GetUserList',
type: 'get',
response: () => {
const list = []
for (let i = 0; i < randomNum(1, 10); i++) {
list.push({ user }.user)
}
return Respones.ok(list)
}
},
{
url: '/api/User/Add',
type: 'post',
response: ({ body }) => {
return Respones.ok(Object.assign({}, { user }.user, body))
}
},
{
url: '/api/User/Delete\.*',
type: 'get',
response: ({ query }) => {
if (!query.id) {
return Respones.failed('请指定要删除的用户')
}
return Respones.ok(Object.assign({}, { user }.user, query))
}
}
]
mock\index.js
const Mock = require('mockjs')
const { param2Obj } = require('./utils')
const Login = require('./Login')
const User = require('./User')
const mocks = [
...Login,
...User
]
// for front mock
// please use it cautiously, it will redefine XMLHttpRequest,
// which will cause many of your third-party libraries to be invalidated(like progress event).
function mockXHR() {
// mock patch
// https://github.com/nuysoft/Mock/issues/300
Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send
Mock.XHR.prototype.send = function() {
if (this.custom.xhr) {
this.custom.xhr.withCredentials = this.withCredentials || false
if (this.responseType) {
this.custom.xhr.responseType = this.responseType
}
}
this.proxy_send(...arguments)
}
function XHR2ExpressReqWrap(respond) {
return function(options) {
let result = null
if (respond instanceof Function) {
const { body, type, url } = options
// https://expressjs.com/en/4x/api.html#req
result = respond({
method: type,
body: JSON.parse(body),
query: param2Obj(url)
})
} else {
result = respond
}
return Mock.mock(result)
}
}
for (const i of mocks) {
Mock.mock(new RegExp(i.url), i.type || 'get', XHR2ExpressReqWrap(i.response))
}
}
module.exports = {
mocks,
mockXHR
}
mock\mock-server.js
const chokidar = require('chokidar')
const bodyParser = require('body-parser')
const chalk = require('chalk')
const path = require('path')
const Mock = require('mockjs')
const mockDir = path.join(process.cwd(), 'mock')
function registerRoutes(app) {
let mockLastIndex
const { mocks } = require('./index.js')
const mocksForServer = mocks.map(route => {
return responseFake(route.url, route.type, route.response)
})
for (const mock of mocksForServer) {
app[mock.type](mock.url, mock.response)
mockLastIndex = app._router.stack.length
}
const mockRoutesLength = Object.keys(mocksForServer).length
return {
mockRoutesLength: mockRoutesLength,
mockStartIndex: mockLastIndex - mockRoutesLength
}
}
function unregisterRoutes() {
Object.keys(require.cache).forEach(i => {
if (i.includes(mockDir)) {
delete require.cache[require.resolve(i)]
}
})
}
// for mock server
const responseFake = (url, type, respond) => {
return {
url: new RegExp(`${process.env.BASE_URL || ''}${url}`),
type: type || 'get',
response(req, res) {
console.log('request invoke: ' + req.path)
res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond))
}
}
}
module.exports = app => {
// parse app.body
// https://expressjs.com/en/4x/api.html#req.body
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({
extended: true
}))
const mockRoutes = registerRoutes(app)
var mockRoutesLength = mockRoutes.mockRoutesLength
var mockStartIndex = mockRoutes.mockStartIndex
// watch files, hot reload mock server
chokidar.watch(mockDir, {
ignored: /mock-server/,
ignoreInitial: true
}).on('all', (event, path) => {
if (event === 'change' || event === 'add') {
try {
// remove mock routes stack
app._router.stack.splice(mockStartIndex, mockRoutesLength)
// clear routes cache
unregisterRoutes()
const mockRoutes = registerRoutes(app)
mockRoutesLength = mockRoutes.mockRoutesLength
mockStartIndex = mockRoutes.mockStartIndex
console.log(chalk.magentaBright(`\n > Mock Server hot reload success! changed ${path}`))
} catch (error) {
console.log(chalk.redBright(error))
}
}
})
}
vue.config.js
const config = {
publicPath: process.env.VUE_APP_PUBLIC_PATH || '/',
lintOnSave: process.env.NODE_ENV !== 'production',
devServer: {
proxy: process.env.NODE_ENV !== 'production' ? {
'/api': {
target: process.env.VUE_APP_URL,
ws: false, // 需要websocket 开启
pathRewrite: {
'^/api': ''
}
}
} : {}
}
}
if (process.env.VUE_MOCK === 'true') {
delete config.devServer.proxy
config.devServer.before = require('./mock/mock-server.js')
}
module.exports = config
编写api
src\api\Login.js
import request from './axios'
/**
* 用户(用户名+密码)登录
* @param {String} name 用户名
* @param {String} pwd 密码
*/
export const loginByUsername = (name, pwd) => {
if (!name || !pwd) {
return Promise.reject()
}
return request({
url: '/api/Login/Login',
method: 'get',
headers: {
isToken: false
// 'Authorization': 'Basic dWx0cmFsYWI6Zm1hc3Rlcg=='
},
params: { name, pwd }
})
}
/**
* 退出登录
*/
export const logout = () => {
return request({
url: '/api/Login/Logout',
method: 'get'
})
}
src\api\User.js
import request from './axios'
/**
* 获取当前登录用户信息
*/
export const getCurrentUser = () => {
return request({
url: '/api/User/GetCurrentUser',
method: 'get'
})
}
/**
* 新增用户
* @param {Object} data 用户对象
* @param {String} data.realname 姓名
* @param {String} data.name 账号
* @param {String} data.pwd 密码
* @param {Number} data.role 角色,默认1(学生)
*/
export const add = (data = {}) => {
// return Promise.resolve(data)
return request({
url: '/api/User/Add',
method: 'post',
data
})
}
/**
* 删除用户
* @param {String} id 用户ID,多个用户英文逗号隔开
*/
export const remove = (id) => {
return request({
url: '/api/User/Delete',
method: 'get',
params: {
id
}
})
}
/**
* 获取用户列表
*/
export const getList = () => {
// return Promise.resolve([
// { id: 1, name: 'admin', realname: '管理员', role: 0 },
// { id: 2, name: 'teacher', realname: '老师', role: 0 },
// { id: 3, name: 'student', realname: '学生', role: 1 }
// ])
return request({
url: '/api/User/GetUserList',
method: 'get'
})
}
api调用
import { getCurrentUser } from '@/api/User'
getCurrentUser()
.then(res => {
console.log(res)
})
.catch(err => {
console.error(err )
})