项目目录结构

3.请求处理

项目中使用mock-server开启本地服务API接口,使得前端与后端项目都可单独进行开发;模拟后端接口的配置文件统一放置在@/mock/文件夹下面

3.1使用mockjs模拟后端API

index.js  ##mock配置文件
mock-server.js  ##mock本地服务配置
table.js
user.js   ##用户的后端API响应数据
utils.js

3.2模拟后端接口

module.exports = [
  // user login
  {
    url: "/vue-admin-template/user/login",
    type: "post",
    response: config => {
      const { username } = config.body;  //获取req.body.username
      const token = tokens[username];    //获取用户的tookens

      // mock error
      if (!token) {
        return {
          code: 60204,
          message: "Account and password are incorrect."
        };
      }

      return {
        code: 20000,
        data: token   //验证成功,返回token数据
      };
    }
  }]

3.3axios发起ajax请求

使用vuex进行状态管理,配置了请求拦截器

getTokenauth.js中配置好了,这个文件中还配置了一系列的对token的操作函数

// request interceptor
service.interceptors.request.use(
  config => {
    // do something before request is sent

    if (store.getters.token) {
      // let each request carry token
      // ['X-Token'] is a custom headers key
      // please modify it according to the actual situation
      config.headers['X-Token'] = getToken() //设置header中的token
    }
    return config
  },
  error => {
    // do something with request error
    console.log(error) // for debug
    return Promise.reject(error)
  }
)

配置响应拦截器

  • 后端的错误状态码,可以自己定义

  • 当后端正常响应,并且返回错误代码时,使用Promise返回一个reject,在路由处用catch进行捕获

service.interceptors.response.use( response => {
    const res = response.data

    // if the custom code is not 20000, it is judged as an error.
    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) {
        // to re-login
        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

4.前端路由跳转

@/src/layout/目录下配置了页面的布局,因为vue-element-admin是一个后台管理系统,因此也仅仅只含有一个布局;

@/src/router/目录下配置了整个前端路由;在路由跳转时,采用transition动画特效

  <section class="app-main">
    <transition name="fade-transform" mode="out-in">
      <router-view :key="key" />
    </transition>
  </section>

5.组件使用封装好的API

@/src/api/table 目录下就封装了一个getlsit()`函数,用于直接操作request的请求

export function getList(params) {
  return request({
    url: "/vue-admin-template/table/li1st1",
    method: "get",
    params
  });
}

错误的处理,在错误到达组件之前就已经被axios响应拦截器给处理掉了,但是在组件那会返回一个Promise.reject对象;不对它进行处理也没有关系,但是会在后台打印一个Promise错误

createError.js?2d83:16 Uncaught (in promise) Error: Request failed with status code 404
    at createError (createError.js?2d83:16)
    at settle (settle.js?467f:18)
    at XMLHttpRequest.handleLoad (xhr.js?b50d:59)

6.Vuex用于组件间的通信

  • 声明user组件的state数据

const getDefaultState = () => {
  return {
    token: getToken(),
    name: '',
    avatar: ''
  }
}
const state = getDefaultState()
  • 定义mutations方法

    这些数据都是从cookie中获得的

    • 重置state内部的数据

    • 设置cookie

    • 设置用户名

    • 设置用户头像

const mutations = {
  RESET_STATE: (state) => {
    Object.assign(state, getDefaultState())
  },
  SET_TOKEN: (state, token) => {
    state.token = token
  },
  SET_NAME: (state, name) => {
    state.name = name
  },
  SET_AVATAR: (state, avatar) => {
    state.avatar = avatar
  }
}
  • 定义异步操作

    使用action进行异步操作,例如登录操作;这个操作在发起Ajax请求得到数据后返回一个Promise对象

const actions = {
  // user login
  login({ commit }, userInfo) {
    const { username, password } = userInfo
    return new Promise((resolve, reject) => {
      login({ username: username.trim(), password: password }).then(response => {
        const { data } = response
        commit('SET_TOKEN', data.token)
        setToken(data.token)
        resolve()
      }).catch(error => {
        reject(error)
      })
    })
  },
  • 组合多个module

    • 在根store中,指定组合多个模块

    • 在getters中指定封装在根store的state

const store = new Vuex.Store({
  modules: {
    app,
    settings,
    user
  },
  getters
})

参考

Last updated