【Vue】Vue-cli之Mock.js 模拟数据实现及构建

Mock 数据是前端开发过程中必不可少的一环,是分离前后端开发的关键链路。通过预先跟服务器端约定好的接口,模拟请求数据甚至逻辑,能够让前端开发更加独立自主,不会被服务端的开发所阻塞。

以下介绍了Mock使用的基础语法,小伙伴们也可直接拿来主义,配合Vscode live-server插件愉快的 进行调试啦~

<pre id="show"></pre>
<img src="" alt="" srcset="" id="imgSrc">

<script>
   var data = Mock.mock({
      'list|1-10': [{
         'id|+1': "@increment"
       }]
    })

    console.log(data.list)

    //document.getElementById("imgSrc").setAttribute("src", data.list[0].id)
    document.getElementById("show").innerHTML = JSON.stringify(data, null, 4)

那如何在Vue脚手架中使用呢?

1. 本地代理解决跨域, devServer->proxy  具体实现可百度
2. 开发环境利用devServer->after中间件、构建使用Mock自定义XHR拦截

  • 中间件为真实XHR请求,控制台有Network日志,Mock为自定义XHR拦截

3. 模块封装、分块


具体流程图如下,如有错误或更好实现,欢迎评论分享

Node-Mock模拟数据实现(流程图)
Node-Mock模拟数据实现(流程图)



1. 工程目录准备,以下实现仅供参考,代码参考传送门: 基于Vue-cli的Mock封装

├── mock                      // mock 模拟数据 与src同级
│   ├── index.js              // 数据总入口
│   ├── mock-server.js        // 数据服务层  
│   ├── table.js              // 数据块

mock-server Node中间件拦截实现,注入方式

devServer: {
  ….
  after: require('./mock/mock-server.js')
}

数据块table.js,实现对单组接口进行统一的定义

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
        }
      }
    }
  }
  ... // 更多
]

index.js 模拟数据的导入导出,路由批量注册,以及公用逻辑实现,同时兼容了Mock和中间件的使用

import Mock from 'mockjs'
import { param2Obj } from '../src/utils' // 返回请求对象

import table from './table'

const mocks = [
  ...table
]

// 重新定义XMLHttpRequest,针对Mock
export function mockXHR() {
  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
        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))
  }
}

// 返回对应请求值 针对中间件
const responseFake = (url, type, respond) => {
  return {
    url: new RegExp(`/mock${url}`),
    type: type || 'get',
    response(req, res) {
      res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond))
    }
  }
}

export default mocks.map(route => {
  return responseFake(route.url, route.type, route.response)
})

main.js  当前运行环境判定挂载mock对象,

// main.js 开启mock 服务
import { mockXHR } from '../mock'
if (process.env.NODE_ENV === 'development') {
  mockXHR()
}

中间件逻辑实现分两部分进行讲述,第一节是路由的批量注册,第二节是文件监听实现自动重启服务,

const chokidar = require('chokidar')
const bodyParser = require('body-parser')s
const chalk = require('chalk')
const path = require('path')

const mockDir = path.join(process.cwd(), 'mock')

function registerRoutes(app) {
  let mockLastIndex
  const { default: mocks } = require('./index.js')
  for (const mock of mocks) {  // [{}] 直接遍历 
    app[mock.type](mock.url, mock.response)
    mockLastIndex = app._router.stack.length
  }
  const mockRoutesLength = Object.keys(mocks).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)]
    }
  })
}

代码逻辑:请求、响应头解析,注册监听逻辑、清除缓存、响应服务

module.exports = app => {
  // es6 polyfill
  require('@babel/register')

  app.use(bodyParser.json())
  app.use(bodyParser.urlencoded({
    extended: true
  }))

  const mockRoutes = registerRoutes(app)
  var mockRoutesLength = mockRoutes.mockRoutesLength
  var mockStartIndex = mockRoutes.mockStartIndex

  // 监听文件变化,热更新服务器
  chokidar.watch(mockDir, {
    ignored: /mock-server/,
    ignoreInitial: true
  }).on('all', (event, path) => {
    if (event === 'change' || event === 'add') {
      try {
        // 删除对应文件映射路由堆栈
        app._router.stack.splice(mockStartIndex, mockRoutesLength)

        // 清除路由缓存
        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))
      }
    }
  })
}


 

发布了18 篇原创文章 · 获赞 7 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_41597258/article/details/86534076