一、背景
- 前端開發需要依賴后端接口
- 后端接口輸出慢、接口規范隨時可能會變,而前端毫無感知
- 前端需要自己 mock 假數據 json 文件
- 假數據 json 數據內容是靜態的,測試不同返回情況需要修改 json 文件
...
因此我們需要一種可以幫我們構造數據的工具,並解決以上的若干痛點
mock.js 是一個不錯的工具
二、安裝與使用
安裝
yarn add mockjs -D
使用
// 使用 Mock
import Mock from 'mockjs'
Mock.mock('http://test.com/getjson.json', 'get', {
// 屬性 list 的值是一個數組,其中含有 1 到 10 個元素
'list|1-10': [{
// 屬性 id 是一個自增數,起始值為 1,每次增 1
'id|+1': 1
}]
})
三、常用構造指令
以下示例可以在
http://mockjs.com/examples.html
網頁上打開控制台
使用Mock.mock({示例代碼})
查看生成的結果
1、時間戳:
'name|1564577990837-2564577990837': 0
2、id
'name|1-123456789': 0
// 6174430
3、指定長度范圍,隨機中文字符
name: '@cword(2, 6)'
// 價親三身千然
'name|2-6': '@cword(1)'
4、指定長度范圍,隨機英文字符
name: '@word(1, 10)'
// yyuj
'name|1-10': '@word(1)'
5、http url
name: '@url(http)'
// "http://djldfusj.in/ccnknb"
6、生成布爾值,false/true各一半幾率
'name|1': true
7、包含小數數字
'name|1-100.3': 1
// 63.895
8、隨機選擇數組中的元素
'name|1': ['AMD', ''CMD, 'UMD']
// 隨機出現數組中的元素
9、萬能的正則
(1)時間戳
name: /170\d{10}/
// 1705237332101
(2)小數數字
name: /\d{2}\.\d{3}/
// 78.635
(3)id
name: /\d{1,9}/
// 651866094
(4)英文字符串
name: /\W{1,3}/
// DvX
(5)中文字符串
name: /[\u4e00-\u9fa5]{1,9}/
// 風我齤劉杌菦炧荷岆
四、從零開始完成一個使用例子
#1、創建環境
yarn global add @vue/cli
- 安裝 vuecli3.x 環境
vue create mock-demo
--- 創建項目mock-demo
- 選擇 default (babel, eslint)
- 選擇 Use Yarn
- 安裝依賴
- 安裝 axios
yarn add axios
- 安裝 mockjs
yarn add mockjs -D
- 安裝 axios
- 運行項目
yarn serve
- 按照命令中顯示的項目地址,用瀏覽器打開
#2、封裝 axios
- 在 src 下創建 utils 目錄,在 utils 下創建 fetch.js 文件
// fetch.js
import axios from 'axios'
export default class baseRequest {
constructor(baseURL) {
baseURL = baseURL || window.location.origin
this.$http = axios.create({
timeout: 30000,
baseURL
})
this.$http.interceptors.request.use(async config => {
return config
})
this.$http.interceptors.response.use(
({ data, config }) => {
if (data.code === 0) {
return data
} else {
return Promise.reject(data)
}
},
e => {
console.log(e, '報錯了')
return Promise.reject({
msg: '網絡開小差了,請稍后重試'
})
}
)
}
post(url, params = {}, config = {}) {
return this.$http.post(url, params, config)
}
get(url, params = {}, config = {}) {
return this.$http.get(url, {
params,
...config
})
}
}
#3、封裝 api 接口
- 在 src 下創建 service 目錄,在 service 下創建 bilibili-server.js 文件
// bilibili-server.js
// 在本例子中,我們將獲取 bilibili 的最近更新番劇接口作為例子
import fetch from '@/utils/fetch.js'
let axios = new fetch()
export const getLastestAnima = () => {
return axios.get('/api/timeline_v2_global')
}
#4、調用獲取番劇接口
- 在 src 下的 App.vue 文件中,created 生命周期中調用
// App.vue
import HelloWorld from './components/HelloWorld.vue'
import { getLastestAnima } from '@/service/bilibili-server.js'
export default {
name: 'app',
components: {
HelloWorld
},
async created() {
try {
let data = await getLastestAnima()
console.log('getLastestAnima:data:>>>', data)
} catch (error) {
console.log('getLastestAnima:error:>>>', error)
}
}
}
#5、設置代理
- 因為跨域限制,所以需要本地設置代理,才能訪問 bilibili 的接口
- 在項目根目錄下創建 vue.config.js 文件
// vue.config.js
module.exports = {
devServer: {
disableHostCheck: true,
open: true, // 是否打開頁面
host: '0.0.0.0',
port: 80,
https: false,
hotOnly: true,
proxy: {
'/api': {
target: 'https://bangumi.bilibili.com',
changeOrigin: true
}
}
}
}
- 重啟項目,然后打開項目,在瀏覽器控制台可以看到已經將獲取到的數據打印出來了
#6、加入 mockjs
1). 在 src 下 創建 mock 目錄
2). 在 mock 下創建 index.js 文件,用來注冊各個 mock 接口
// /src/mock/index.js
// 使用 Mock
import Mock from 'mockjs'
import modules from './modules'
// 注冊每個 mock api
for (let key in modules) {
let module = modules[key]
// console.log('module:>>>', module)
Mock.mock(...module)
}
3). 在 mock 下創建 modules,用來分類放置各個微服務相對應的 mock 接口
目錄構成
modules
bilibili-server // 微服務
get-lastest-anima.js // mock 接口
index.js // 用來導出每個微服務下的所有 mock 接口
// /src/mock/modules/bilibili-server/get-lastest-anima.js.js
/* eslint-disable no-console */
import { host } from "../../utils/host"
import { formatMockData } from "../../utils/util"
import Mock from "mockjs"
const formatData = formatMockData("", "", "", {
code: 0,
'result|0-100': [
{
'area|1': ["日本", '美國', '國產'],
'arealimit|0-923456789': 0,
'attention|0-923456789': 0,
'bangumi_id|0-923456789': 0,
'bgmcount|1': [/\d{1,6}/, 'SP'],
cover: '@url(http)',
'danmaku_count|0-923456789': 0,
'ep_id|-1-923456789': 0,
'favorites|0-923456789': 0,
'is_finish|1': [0, 1],
'lastupdate|0-1966120600': 0,
'lastupdate_at': '@datetime',
'new|1': true,
'play_count|0-923456789': 0,
pub_time: '@datetime',
'season_id|0-9123456789': 5978,
'season_status|0-9123456789': 13,
'spid|0-9123456789': 0,
square_cover: '@url(http)',
title: "@cword(1,20)",
'viewRank|0-912345678': 0,
'weekday|1': [0, 1, 2, 3, 4, 5, 6]
}
],
message: '@cword(1,10)'
})
let url = host + "/api/timeline_v2_global"
let method = "get"
export default [
url,
method,
function(options) {
console.log("options:>>>", options)
return Mock.mock(formatData)
},
{
url,
method,
formatData
}
]
// /src/mock/modules/index.js
import getLastestAnima from './bilibili-server/get-lastest-anima'
export default {
getLastestAnima
}
4). 在 mock 目錄下創建 utils,用來放置工具類
utils
host.js
util.js
// /src/mock/utils/host.js
let h = window.location.origin
export const host = h || ''
// /src/mock/utils/util.js
export const formatMockData = (
mockData = {},
codeStatus = 0,
msg = '@cword(1,10)',
customData
) => {
if (customData) return customData
let initFormatObj = {
code: codeStatus,
result: mockData,
msg: msg
}
return initFormatObj
}
// 組合數據
export const comp = function(value) {
return [null, '', value]
}
5). 最后在項目的 main.js 中引入 mock 入口文件
// /src/main.js
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
// 開發環境使用,生產環境注釋
import '@/mock'
new Vue({
render: h => h(App),
}).$mount('#app')
#7、反向校驗后端 api 返回數據
1). 在 mock 目錄下的 utils 目錄下 創建 proxy-valid.js 文件
// 反向校驗后端 api 配置文件
/* eslint-disable no-console */
import Mock from 'mockjs'
import modules from '../modules'
export default function(url, method, data) {
Object.keys(modules).forEach(key => {
let ele = modules[key][3]
if (ele && ele.url === url && ele.method === method) {
let validResult = Mock.valid(ele.formatData, data)
// 驗證通過,則不用輸出信息
if (validResult && validResult.length === 0) {
return
}
console.group(url.replace(/http:\/\//, ''))
console.log('valid response data :>>> url: ', url)
console.log('valid response data :>>> validMsg: ', validResult)
console.groupEnd()
}
})
}
2). 修改 /src/utils/fetch.js
/* eslint-disable no-console */
import axios from 'axios'
// 開發環境使用,打包前注意要注釋
import proxyValid from '@/mock/utils/proxy-valid.js'
export default class baseRequest {
constructor(baseURL) {
baseURL = baseURL || window.location.origin
this.$http = axios.create({
timeout: 30000,
baseURL
})
this.$http.interceptors.request.use(async config => {
return config
})
this.$http.interceptors.response.use(
({ data, config }) => {
// 開發環境需要,生產環境需要注釋
proxyValid(config.url, config.method, data)
if (data.code === 0) {
return data
} else {
return Promise.reject(data)
}
},
e => {
console.log(e, '報錯了')
return Promise.reject({
msg: '網絡開小差了,請稍后重試'
})
}
)
}
post(url, params = {}, config = {}) {
return this.$http.post(url, params, config)
}
get(url, params = {}, config = {}) {
return this.$http.get(url, {
params,
...config
})
}
}
此時,一個完整的 數據 mock 和反向校驗 demo 就完成了
五、根據請求的數據修改 mock 已經生成的數據
根據前端請求的參數,修改 mock 渲染好的數據,然后返回給前端
這樣實現根據不同的參數返回:
1、成功狀態
2、失敗狀態
3、其他異常狀態
/* eslint-disable no-console */
import { host } from "../../utils/host"
import { formatMockData } from "../../utils/util"
import Mock from "mockjs"
const formatData = formatMockData("", "", "", {
code: 0,
'result|0-100': [
{
'area|1': ["日本", '美國', '國產'],
'arealimit|0-923456789': 0,
'attention|0-923456789': 0,
'bangumi_id|0-923456789': 0,
'bgmcount|1': [/\d{1,6}/, 'SP'],
cover: '@url(http)',
'danmaku_count|0-923456789': 0,
'ep_id|-1-923456789': 0,
'favorites|0-923456789': 0,
'is_finish|1': [0, 1],
'lastupdate|0-1966120600': 0,
'lastupdate_at': '@datetime', // bilibili 這邊返回的接口中,有時候這個屬性會少,導致反向校驗出錯
'new|1': true,
'play_count|0-923456789': 0,
pub_time: '@datetime',
'season_id|0-9123456789': 5978,
'season_status|0-9123456789': 13,
'spid|0-9123456789': 0,
square_cover: '@url(http)',
title: "@cword(1,20)",
'viewRank|0-912345678': 0,
'weekday|1': [0, 1, 2, 3, 4, 5, 6]
}
],
message: '@cword(1,10)'
})
let url = host + "/api/timeline_v2_global"
let method = "get"
export default [
url,
method,
function(options) {
console.log("options:>>>", options)
// options:
// body: null
// type: "GET"
// url: "http://localhost:1385/api/timeline_v2_global"
// 此處 body 就是前端請求的參數集合
// 在此處可以根據 body 里面的參數,來修改 Mock.mock(formatData) 渲染后的數據
// 比如 修改 code = 404
// 設置各種成功、異常狀態
return Mock.mock(formatData)
},
{
url,
method,
formatData
}
]