Vue 中使用mockjs模擬后端數據


關於mockjs,官網描述的是

1.前后端分離

2.不需要修改既有代碼,就可以攔截 Ajax 請求,返回模擬的響應數據。

3.數據類型豐富

4.通過隨機數據,模擬各種場景。

等等優點。

總結起來就是在后端接口沒有開發完成之前,前端可以用已有的接口文檔,在真實的請求上攔截ajax,並根據mockjs的mock數據的規則,模擬真實接口返回的數據,並將隨機的模擬數據返回參與相應的數據交互處理,這樣真正實現了前后台的分離開發。

與以往的自己模擬的假數據不同,mockjs可以帶給我們的是:在后台接口未開發完成之前模擬數據,並返回,完成前台的交互;在后台數據完成之后,你所做的只是去掉mockjs:停止攔截真實的ajax,僅此而已。
接下來就一步一步實現這個過程:

1.引入js依賴

npm install mockjs --save-dev

2.建一個mock文件夾來統一管理我們的mock數據

3.在mockjs下面新建幾個模擬數據文件

import Mock from 'mockjs'
 
const data = Mock.mock({  // 模擬數據生成,遵循Mock語法規范
  'items|30': [{
    id: '@id',
    title: '@sentence(10, 20)',
    'status|1': ['published', 'draft', 'deleted'],
    author: 'name',
    display_time: '@datetime',
    pageviews: '@integer(300, 5000)'
  }]
})
 
export default [  
  // 路由攔截,返回指定格式數據
  // 以下格式為兼容after中間件攔截、返回要求
  {
    url: '/table/list',
    type: 'get',
    response: config => {
      const items = data.items
      return {
        code: 20000,
        data: {
          total: items.length,
          items: items
        }
      }
    }
  }
  ... // 更多
]

 

4.在mock文件夾下建一個index.js

5.在mock/index.js中寫關鍵代碼,攔截到我們前端發出的請求

const Mock = require("mockjs");
const { param2Obj } = require("./utils"); //解析地址欄參數的函數
// 導入模擬數據
const creditEvaluateStatistics = require("./credit-evaluate-statistics");

const mocks = [...creditEvaluateStatistics];

// 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) {
    console.log("respond:", respond);
    return function (options) {
      console.log("options:", 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) {
    console.log(i);
    Mock.mock(
      new RegExp(i.url),
      i.type || "get",
      XHR2ExpressReqWrap(i.response)
    );
  }
}

module.exports = {
  mocks,
  mockXHR,
};

 

utile.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;
}

module.exports = {
  param2Obj,
  deepClone,
};
6.main.js文件中引入
// main.js 開啟mock 服務
import { mockXHR } from '../mock'
if (process.env.NODE_ENV === 'development') {
  mockXHR()

7.封裝請求方法

import axios from "axios";
import { Loading, Message } from "element-ui";
import store from "@/store";
// import { getToken } from "@/utils/auth";

// create an axios instance
const service = axios.create({
  // baseURL: "", 
  timeout: 10000, // request timeout
  // headers: {
  //   "Content-Type": "multipart/form-data",
  // },
});

let apiCallNo = 0;
let loadingInstance;

// request interceptor
// TODO 待優化
service.interceptors.request.use(
  (config) => {
    if (config.data) {
      const { hideLoading, ...rest } = config.data;
      if (!hideLoading) {
        apiCallNo += 1;
        if (apiCallNo === 1) {
          loadingInstance = Loading.service();
        }
      }
      if (Object.keys(rest).length !== 0) {
        config.data = rest;
      } else if (typeof hideLoading === "boolean") {
        config.data = null;
      }
    } else {
      apiCallNo += 1;
      if (apiCallNo === 1) {
        loadingInstance = Loading.service();
      }
    }

    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();
    }
    return config;
  },
  (error) => {
    // do something with request error
    return Promise.reject(error);
  }
);

// response interceptor
service.interceptors.response.use(
  /**
   * If you want to get http information such as headers or status
   * Please return  response => response
   */

  /**
   * Determine the request status by custom code
   * Here is just an example
   * You can also judge the status by HTTP Status Code
   */
  (response) => {
    apiCallNo -= 1;
    if (apiCallNo === 0) {
      loadingInstance.close();
    }
    const res = response.data;

    // 導出二進制流數據
    if (res.type) {
      return res;
    }
    // 普通請求
    if (res.status !== 200) {
      Message({
        message: res.message || "Error",
        type: "error",
        duration: 5 * 1000,
      });
      return Promise.reject(new Error(res.message || "Error"));
      // 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();
      //     });
      //   });
      // }
    } else {
      return res.data;
    }
  },
  (error) => {
    console.log(error.response);
    apiCallNo -= 1;
    if (apiCallNo === 0) {
      loadingInstance.close();
    }
    Message({
      message: error.response?.data.message ?? "網絡異常,請重試", // TODO 是否要改成統一的提示?
      type: "error",
      duration: 5 * 1000,
    });
    return Promise.reject(error);
  }
);

export default service;

8.新建一個文件專門封裝api

import request from "@/utils/request"; // 引入request方法
// 使用mock模擬后端數據
export function fetchResultTrend(params) {
  return request({
    url: "/mock/credit-evaluate-statistics/result/trend",
    params,
  });
}

9.在vue文件中調用接口

async closerRateChange() {
      const res = await fetchResultTrend();
      console.log(res)
}

經過以上步驟我們就順利實現了mockjs模擬數據的過程。
mockjs官網地址:
http://mockjs.com/examples.html
https://github.com/nuysoft/Mock/wiki/Getting-Started


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM