zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    vue3+typescript引入外部文件
    vue项目中使用sass
    关于Vue.use()使用详解
    案例:密码框格式提示信息错误
    案例:显示隐藏文本框里面的内容
    案例:循环精灵图案例
    案例:关闭淘宝二维码案例
    案例: 仿京东显示隐藏密码
    案例:根据系统时间显示不同的问候语
    ES6中类和对象的注意问题
  • 原文地址:https://www.cnblogs.com/lyt0207/p/13618060.html
Copyright © 2011-2022 走看看