vue3之vite配置vite-plugin-mock使用mock轻松创建模拟数据提高开发效率

简介: vue3之vite配置vite-plugin-mock使用mock轻松创建模拟数据提高开发效率

什么是Mock数据

Mock 可以翻译为“模拟”,在前端开发中通常指模拟后端接口和数据。


在软件开发过程中,Mock数据指的是一种虚拟的测试数据,用于模拟真实的数据情况。它可以用来替代真实的数据源,从而实现在没有真实数据的情况下进行开发和测试的需求。


我们在开发的时候,一般都是前后端同时开发,尤其是某些后台系统开发时,很多前端同学分分钟就可以做完静态页面的开发,然后就是摸鱼时间,等待后端的接口。如果你的后端同事非常配合,愿意在设计数据库的时候顺便定好返回的数据结构和字段,并且联调时间很紧张的时候,这时候你应该考虑着手去做一下前端 mock,为联调争取时间。


Mock数据的使用不仅可以提高开发效率,还可以避免与真实数据源的依赖性,减少开发过程中的等待时间,以及降低测试环境的复杂性。

使用Mock数据的优点

简单性:不需要复杂的配置和部署过程,可以快速地创建和管理模拟数据。

灵活性:可以满足不同的开发需求,例如支持不同的请求类型、不同的请求方式等。

真实性:能够生成更接近真实的数据,可以模拟不同的数据类型、格式和结构。

维护性:可以方便地更新和修改模拟数据。

合作性: 可以在团队内方便的共享模拟数据。


Mock数据使用步骤

一、安装依赖mockjs、vite-plugin-mock

提供本地和生产模拟服务。

vite 的数据模拟插件,是基于 vite.js 开发的。 并同时支持本地环境和生产环境。 Connect 服务中间件在本地使用,mockjs 在生产环境中使用。

npm i mockjs vite-plugin-mock --save-dev


二、vite.config.ts 文件中配置

// vite.config.ts
import { defineConfig } from 'vite'
import { viteMockServe } from 'vite-plugin-mock'
import vue from '@vitejs/plugin-vue'

export default defineConfig(({ command }) => {
  return {
    plugins: [
      vue(),
      viteMockServe({
        mockPath: 'mock', // mock文件夹路径
        enable: command === 'serve' // 只有开发环境才开启mock
      }),
    ],
  }
})
  • viteMockServe 配置
{
    mockPath?: string;
    ignore?: RegExp | ((fileName: string) => boolean);
    watchFiles?: boolean;
    enable?: boolean;
    ignoreFiles?: string[];
    configPath?: string;
    logger?:boolean;
}
参数 类型 默认值 说明
mockPath string mock 设置模拟.ts 文件的存储文件夹
ignore RegExp undefined 自动读取模拟.ts 文件时,请忽略指定格式的文件
watchFiles boolean true 设置是否监视mockPath对应的文件夹内文件中的更改
enable boolean true 是否启用 mock 功能
configPath string vite.mock.config.ts 设置模拟读取的数据条目
logger boolean true 是否在控制台显示请求日志


三、在根目录下创建mock文件

项目文件夹下新建mock文件夹,用于存放本地mock文件

// mock/user.ts

const createUserList = () => {
    return [
        {
            userId: 1,
            avatar: 'https://pic1.zhimg.com/80/v2-083faf550543c1e9f134b56b3322ee3c_720w.webp',
            username: 'admin',
            password: '123456789',
            desc: '下船不谈船里事',
            roles: ['平台管理员'],
            buttons: ['cuser.detail'],
            routes: ['home'],
            token: 'Admin Token'
        },
        {
            userId: 2,
            avatar: 'https://pic1.zhimg.com/80/v2-e1427f6a21122ac163ff98d24f55d372_720w.webp',
            username: 'system',
            password: '123456789',
            desc: '旧人不谈近况,新人不讲过往',
            roles: ['系统管理员'],
            buttons: ['cuser.detail', 'cuser.user'],
            routes: ['home'],
            token: 'Admin Token'
        }
    ]
}
export default [
    // 用户登录接口
    {
        url: '/api/user/login',
        method: 'post',
        response: ({ body }: any) => {
            // 获取请求体携带过来的用户名与密码
            const { username, password } = body
            // 调用获取用户信息函数,用于判断是否有此用户
            const checkUser = createUserList().find(
                (item) => item.username === username && item.password === password
            )
            // 没有用户则返回失败信息
            if (!checkUser) {
                return {
                    code: 201,
                    data: {
                        message: '账号或者密码不正确'
                    }
                }
            }
            // 如果有返回成功信息
            const { token } = checkUser
            return {
                code: 200,
                data: {
                    token
                }
            }
        }
    },
    // 获取用户信息接口
    {
        url: '/api/user/info',
        method: 'get',
        response: (request: any) => {
            // 获取请求头携带的 token
            const token = request.headers.token
            // 查看用户信息数据中是否包含有此 token 的用户
            const checkUser = createUserList().find((item) => item.token === token)
            // 没有就返回失败信息
            if (!checkUser) {
                return {
                    code: 201,
                    data: {
                        message: '获取用户信息失败'
                    }
                }
            }
            // 有就返回成功信息
            return {
                code: 200,
                data: {
                    checkUser
                }
            }
        }
    }
]


四、编写api接口调用文件

1、src文件夹下新建utils/request.ts
// utils/request.ts

import axios from "axios";

//创建一个axios实例
const request = axios.create({
    baseURL: '',
    timeout: 20000,
});


// 添加请求拦截器
request.interceptors.request.use(
    function (config) {
        // 请求地址携带时间戳
        const _t = new Date().getTime()
        config.url += `?${_t}`
        
        // 请求头携带token
        config.headers['token'] = localStorage.getItem('token') || ''

        // 在发送请求之前做些什么
        // console.log('我要准备请求啦------')
        // console.log(config, '请求配置')
        
        return config;
    },
    function (error) {
        // 对请求错误做些什么
        return Promise.reject(error);
    }
);

// 添加响应拦截器
request.interceptors.response.use(
    function (response) {
        // 对响应数据做点什么
        // console.log('我接收到响应数据啦------')
        // console.log(response, '响应配置')
        if (response.status === 200) {
            return Promise.resolve(response.data)
        } else {
            return Promise.reject(response)
        }
    },
    function (error) {
        // 对响应错误做点什么
        if (error && error.response) {
            switch (error.response.status) {
                case 400:
                    error.message = '错误请求';
                    break;
                case 401:
                    error.message = '未授权,请重新登录';
                    break;
                case 403:
                    error.message = '拒绝访问';
                    break;
                case 404:
                    error.message = '请求错误,未找到该资源';
                    break;
                case 405:
                    error.message = '请求方法未允许';
                    break;
                case 408:
                    error.message = '请求超时';
                    break;
                case 500:
                    error.message = '服务器端出错';
                    break;
                case 501:
                    error.message = '网络未实现';
                    break;
                case 502:
                    error.message = '网络错误';
                    break;
                case 503:
                    error.message = '服务不可用';
                    break;
                case 504:
                    error.message = '网络超时';
                    break;
                case 505:
                    error.message = 'http版本不支持该请求';
                    break;
                default:
                    error.message = `未知错误${error.response.status}`;
            }
        } else {
            error.message = "连接到服务器失败";
        }
        return Promise.reject(error);
    }
);


/*
 *  get请求:从服务器端获取数据
 *  url:请求地址
 *  params:参数
 * */
export function get(url:string, params = {}) {
    return new Promise((resolve, reject) => {
        request({
            url: url,
            method: 'get',
            params: params
        }).then(response => {
            resolve(response);
        }).catch(error => {
            reject(error);
        });
    });
}

/*
 *  post请求:向服务器端提交数据
 *  url:请求地址
 *  params:参数
 * */
export function post(url:string, params = {}) {
    return new Promise((resolve, reject) => {
        request({
            url: url,
            method: 'post',
            data: params
        }).then(response => {
            resolve(response);
        }).catch(error => {
            reject(error);
        });
    });
}

// 对外暴露请求方法
export default {
    get,
    post
}
2、src文件夹下新建api/user.ts
// api/user.ts

import { get, post } from './request';

const api = {
    login: '/api/user/login',
    users: '/api/user/info'
}

//登录
export const login = (params: any) => {
    return post(api.login, params).then((res: any) => {
        if (res.code === 200) {
            localStorage.setItem('token', res.data.token);
        }
        return Promise.resolve(res);
    })
}


//获取用户信息
export const getUserInfo = () => {
    const token = localStorage.getItem('token');
    if (!token) return Promise.reject(new Error('用户未登录'));
    return get(api.users);
}


五、业务页面调用

// App.vue

import { onBeforeMount } from 'vue'
import {login,getUserInfo} from "./utils/user"

onBeforeMount(async () => {
  // 登录
  const user = await login({
    username: 'admin',
    password: '123456789'
  })
  console.log(user)
  
  // 获取用户信息
  const users = await getUserInfo()
  console.log(users)
})
//// App.vue

import { onBeforeMount } from 'vue'
import {login,getUserInfo} from "./utils/user"

onBeforeMount(async () => {
  // 登录
  const user = await login({
    username: 'admin',
    password: '123456789'
  })
  console.log(user)
  
  // 获取用户信息
  const users = await getUserInfo()
  console.log(users)
})

六、Mock的用法规则

import mockJS from 'mockjs'

const userList = mockJS.mock({
    // 属性 list 的值是一个数组,其中含有 1 到 10 个元素
    'list|1-10': [
        {
            // 随机生成id号
            id: '@id',
            // 随机生成中文姓名
            name: '@cname',
            // 属性 id 是一个自增数,起始值为 1,每次增 1
            'id|+1': 1,
            // 随机生成ip地址
            ip: '@ip',
            // 随机生成省市区地址
            address:'@county(true)',
            // 随机生成邮政编码
            zip:'@zip',
            // 随机生成18-70之间的年龄
            "age|18-70": 20,
            // 随机生成日期
            date: '@date("yyyy-MM-dd")',
            // 随机生成头像
            avatar:"@image('200x200')",
        }
    ]
})

七、在生产环境中的使用

1、创建mockProdServer.ts 文件
//  mockProdServer.ts

import { createProdMockServer } from 'vite-plugin-mock/client'

// 逐一导入您的mock.ts文件
// 如果使用vite.mock.config.ts,只需直接导入文件
// 可以使用 import.meta.glob功能来进行全部导入
import testModule from '../mock/test'

export function setupProdMockServer() {
  createProdMockServer([...testModule])
}
2、配置 vite-plugin-mock
import { viteMockServe } from 'vite-plugin-mock'

import { UserConfigExport, ConfigEnv } from 'vite'

export default ({ command }: ConfigEnv): UserConfigExport => {
  return {
    plugins: [
      viteMockServe({
        mockPath: 'mock',
        // 根据项目配置。可以配置在.env文件
        enable: true,
      }),
    ],
  }
}
3、注意事项
  • 无法在 mock.ts 文件中使用 node 模块,否则生产环境将失败
  • 模拟数据如果用于生产环境,仅适用于某些测试环境。 不要在正式环境中打开它,以避免不必要的错误。 同时,在生产环境中,它可能会影响正常的 Ajax 请求,例如文件上传/下载失败等。
目录
相关文章
|
13天前
|
缓存 JavaScript UED
Vue3中v-model在处理自定义组件双向数据绑定时有哪些注意事项?
在使用`v-model`处理自定义组件双向数据绑定时,要仔细考虑各种因素,确保数据的准确传递和更新,同时提供良好的用户体验和代码可维护性。通过合理的设计和注意事项的遵循,能够更好地发挥`v-model`的优势,实现高效的双向数据绑定效果。
115 64
|
13天前
|
JavaScript 前端开发 API
Vue 3 中 v-model 与 Vue 2 中 v-model 的区别是什么?
总的来说,Vue 3 中的 `v-model` 在灵活性、与组合式 API 的结合、对自定义组件的支持等方面都有了明显的提升和改进,使其更适应现代前端开发的需求和趋势。但需要注意的是,在迁移过程中可能需要对一些代码进行调整和适配。
|
1月前
|
JavaScript
Vue基础知识总结 4:vue组件化开发
Vue基础知识总结 4:vue组件化开发
|
1月前
|
JavaScript 数据管理 Java
在 Vue 3 中使用 Proxy 实现数据双向绑定的性能如何?
【10月更文挑战第23天】Vue 3中使用Proxy实现数据双向绑定在多个方面都带来了性能的提升,从更高效的响应式追踪、更好的初始化性能、对数组操作的优化到更优的内存管理等,使得Vue 3在处理复杂的应用场景和大量数据时能够更加高效和稳定地运行。
52 1
|
19天前
|
缓存 JavaScript 前端开发
vue学习第四章
欢迎来到我的博客!我是瑞雨溪,一名热爱JavaScript与Vue的大一学生。本文介绍了Vue中计算属性的基本与复杂使用、setter/getter、与methods的对比及与侦听器的总结。如果你觉得有用,请关注我,将持续更新更多优质内容!🎉🎉🎉
34 1
vue学习第四章
|
19天前
|
JavaScript 前端开发
vue学习第九章(v-model)
欢迎来到我的博客,我是瑞雨溪,一名热爱JavaScript与Vue的大一学生,自学前端2年半,正向全栈进发。此篇介绍v-model在不同表单元素中的应用及修饰符的使用,希望能对你有所帮助。关注我,持续更新中!🎉🎉🎉
28 1
vue学习第九章(v-model)
|
19天前
|
JavaScript 前端开发 开发者
vue学习第十章(组件开发)
欢迎来到瑞雨溪的博客,一名热爱JavaScript与Vue的大一学生。本文深入讲解Vue组件的基本使用、全局与局部组件、父子组件通信及数据传递等内容,适合前端开发者学习参考。持续更新中,期待您的关注!🎉🎉🎉
33 1
vue学习第十章(组件开发)
|
25天前
|
JavaScript 前端开发
如何在 Vue 项目中配置 Tree Shaking?
通过以上针对 Webpack 或 Rollup 的配置方法,就可以在 Vue 项目中有效地启用 Tree Shaking,从而优化项目的打包体积,提高项目的性能和加载速度。在实际配置过程中,需要根据项目的具体情况和需求,对配置进行适当的调整和优化。
|
25天前
|
存储 缓存 JavaScript
在 Vue 中使用 computed 和 watch 时,性能问题探讨
本文探讨了在 Vue.js 中使用 computed 计算属性和 watch 监听器时可能遇到的性能问题,并提供了优化建议,帮助开发者提高应用性能。
|
25天前
|
存储 缓存 JavaScript
如何在大型 Vue 应用中有效地管理计算属性和侦听器
在大型 Vue 应用中,合理管理计算属性和侦听器是优化性能和维护性的关键。本文介绍了如何通过模块化、状态管理和避免冗余计算等方法,有效提升应用的响应性和可维护性。