☰
基于Vue3的校园二手交易系统开发实战:从Composition API到前后端联调
2026/10/3 9:55:54 网站建设 项目流程

校园二手交易这个项目,我前前后后带过几届学生做毕设,也自己完整重构过一版,算是踩过不少坑。拿到“基于Vue3的校园二手商品交易系统设计与实现”这个题目时,很多人第一反应是“不就是个增删改查嘛”,但真做起来才会发现,从需求拆分到前端架构,再到前后端联调,每一步都有讲究。这篇文章我尽量把整个从0到1的过程展开来讲,包括为什么用Vue3、Composition API怎么组织代码、商品发布和订单流程怎么设计、Vite和Axios怎么配,以及我实际开发中踩过的那些莫名其妙的坑。

1. 项目需求拆解与系统整体架构

1.1 校园二手场景的特殊性分析

做校园二手交易系统,第一件事不是写代码,而是搞清楚“校园”这两个字到底意味着什么。跟闲鱼、转转这种面向全社会的二手平台相比,校园场景有几个非常明显的差异,这些差异会直接影响你的表结构设计和前端页面规划。

校园用户的交易半径极小,基本锁定在同一个校区甚至同一栋宿舍楼内。这意味着系统不需要复杂的物流追踪,只需要一个“见面交易”的约定流程。所以订单模块里的配送方式基本可以简化为“校内自提”和“约定地点”,这大大降低了开发的复杂度。

用户身份相对可信。学生群体有学号、院系信息,可以通过学生证或在读信息做基础认证。相比全社会平台要求的个人身份认证,校园系统只需要绑定学号就能完成信任基础的搭建。前端登录页面可以设计成“学号+密码”或“手机号+密码”两种方式,后者更利于扩展到其他校园服务。

交易时间有强烈的周期性。开学季教材、宿舍用品需求暴增,毕业季大量闲置物品集中释放。这就是为什么后台管理需要数据统计功能,按时间段看发布量与成交量的趋势,对运营和功能迭代都有帮助。

二手商品的品类高度集中。教材教辅、电子产品、生活用品、运动器材、宿舍神器这五类基本能覆盖绝大多数闲置。前端分类导航按这个维度设计,搜索和筛选时体验会好很多。

明确了这四点,系统的功能边界其实就清晰了:前台以商品发布、浏览、搜索、详情、下单、个人中心为核心闭环;后台以用户管理、商品审核、订单管理、数据统计为核心。会员积分这类花哨功能一律砍掉,优先保证主流程的完整性和可用性。

1.2 为什么选Vue3而不是Vue2

技术选型处处是学问,不是说Vue2不能做,而是Vue3在几个关键点上的优势,对这个项目来说性价比更高。

组合式API的代码组织方式,解决的是业务逻辑复用和可维护性的问题。校园二手系统的核心是商品、订单、用户三个域,如果用Vue2的Options API,每个组件里data、methods、computed各占一块,同一个商品审核的逻辑会被拆散在不同配置项里。而Vue3的setup语法让同一个功能的变量和方法可以放在一起,配合自定义组合式函数(比如useGoods、useOrder),代码的阅读成本和维护成本都会明显降低。尤其是做订单状态切换这种稍微有点逻辑的模块,体验差距非常明显。

响应式系统的底子换了。Vue3用Proxy替代了Vue2的Object.defineProperty,这意味着可以直接监听属性的新增和删除,处理数组下标赋值也更准确。做交易系统时,订单状态从“待付款”改成“已确认”,或者给商品对象动态挂一个收藏标记,这类操作在Vue3里不会出现“数据变了但视图没反应”的玄学问题。

生态已经完全成熟。Element Plus、Vant、Pinia都支持Vue3,Vite的冷启动速度比webpack快一个量级。对做毕设或练习项目的人来说,这能省下大量等待时间,把精力花在业务逻辑上。

我经常跟人说,如果只是想应付一个页面展示,Vue2确实够用。但“系统设计与实现”这个题,审稿老师看的是你的设计能力和工程化思维。Vue3 + Composition API + Pinia + Vite这套组合,本身就是项目设计里一个可以写在文档里的加分项。

1.3 系统模块拆分与前端目录组织

动手写代码前,先把前端目录结构定好。我个人习惯按“功能模块 + 业务域”来组织,而不是单纯按文件类型堆。一个可供参考的目录结构如下:

src/ ├── api/ # 接口请求层 │ ├── goods.js │ ├── order.js │ ├── user.js │ └── auth.js ├── assets/ ├── components/ # 通用组件 │ ├── GoodsCard.vue │ ├── UploadImage.vue │ └── OrderStatusTag.vue ├── composables/ # 组合式函数 │ ├── useGoodsList.js │ ├── useOrderFlow.js │ └── useAuth.js ├── router/ ├── stores/ # Pinia状态 │ ├── user.js │ └── app.js ├── views/ │ ├── home/ │ ├── goods/ │ ├── order/ │ ├── user/ │ └── admin/ └── utils/

这个结构的关键点是composables和stores的分离。composables里放的是“怎么处理数据”的逻辑,比如调用接口、处理分页参数、计算筛选条件;stores里放的是“跨页面共享的数据”,比如登录用户信息、系统配置。把这两层分开,页面组件的职责就被压缩得很薄,只负责模板渲染和事件分发,维护起来非常轻松。

后端接口设计上,电商类系统的标准接口可以按照资源来拆分:登录注册、用户信息、商品发布、商品列表、商品详情、商品状态修改、订单创建、订单状态流转、后台数据统计。每类接口的参数和返回值保持稳定,前端Api层的方法跟后端Controller一一对应。

2. 核心技术点详解:Vue3在项目中怎么用才到位

2.1 Composition API的编排思路

很多初学Vue3的人都会疑惑一个问题:明明Option API写起来也挺顺手的,setup里加了一堆ref和function反而感觉更乱。其实这是没有掌握正确的编排姿势。Composition API的精髓不是把data变成ref,而是按逻辑关注点组织代码。

举个例子,商品列表页涉及的东西有:搜索表单数据、分页状态、列表数据、加载状态、筛选条件、排序规则。如果用Option API,这些相关的东西会被塞进data、methods、computed三个区域,上下翻找非常拧巴。用setup后我习惯这样组织:

const searchForm = ref({ keyword: '', category: '', minPrice: '' }) const pageInfo = reactive({ page: 1, pageSize: 12, total: 0 }) const goodsList = ref([]) const loading = ref(false) async function fetchGoods() { loading.value = true try { const { list, total } = await goodsApi.getList({ ...searchForm.value, ...pageInfo }) goodsList.value = list pageInfo.total = total } finally { loading.value = false } } function handleSearch() { pageInfo.page = 1 fetchGoods() } function handlePageChange(page) { pageInfo.page = page fetchGoods() }

这一组代码放在一起,页面的核心业务流程一目了然。更复杂的场景可以把这部分逻辑抽成组合式函数,放到composables/useGoodsList.js里,让组件只保留一句话调用,页面代码清爽很多。

2.2 ref和reactive的使用选择

Vue3里声明响应式数据有ref和reactive两套方案,我见过不少项目用得很混乱,这里给一个比较实用的判断标准:基础类型的值用ref,对象和数组类型的结构化数据用reactive,但如果你需要整体替换这个数据(比如接口返回后直接赋值一个全新的数组),那优先用ref。

原因在于reactive返回的是原始对象的Proxy,如果你在函数里写成goodsList.value = res.data这种赋值,直接把整个对象换掉的话会丢失响应式,而ref通过.value的代理来包装,整体赋值是安全的。这个坑在商品列表页里最容易出现,从接口拿回新数组赋值给reactive声明的变量,页面死活不更新,查了半天才发现是这个原因。

有一个细节值得单独说:如果你用ref声明一个对象类型的变量,比如商品表单数据const form = ref({}),在模板里用的时候别忘记.value,在脚本里操作也一样。为了少写两个字符写成了const form = reactive({...}),但后续代码里又出现form.value.name这种写法,就会直接报错,这种代码风格混乱问题在多人协作时尤其明显。

响应式数据的性能问题也要注意。商品列表如果有几百上千条数据,每一条都是一个深层的响应式对象,修改其中一条的某个属性会触发大量依赖更新。实际项目中可以给卡片列表用shallowRef或shallowReactive,或者干脆不要每一层都做响应式,只让列表本身是响应式的,铺开渲染时对性能改善非常明显。

2.3 状态管理用Pinia怎么说都得更合适

Vue3项目里状态管理基本默认Pinia,对比Vuex有几个非常实际的体验优势:没有mutations,直接在actions里改状态,代码量直接少了一半;对TypeScript的支持程度更高,做稍微规范一点的项目会舒服很多;store之间可以相互调用,不需要像Vuex那样通过rootState绕来绕去。

交易系统里哪些数据需要全局共享?登录用户信息、搜索历史(可选)、未读数等。以用户信息为例,登录完成后把用户对象存到store中,所有需要显示用户名的组件直接从store里取,不需要走props一层层传递,修改头像和昵称后全站同步更新。Pinia的store设计也很直白:

// stores/user.js import { defineStore } from 'pinia' export const useUserStore = defineStore('user', { state: () => ({ token: localStorage.getItem('token') || '', userInfo: {} }), getters: { isLoggedIn: (state) => !!state.token, userName: (state) => state.userInfo?.name || '未登录' }, actions: { setToken(token) { this.token = token localStorage.setItem('token', token) }, setUserInfo(info) { this.userInfo = info } } })

刷新页面时token从localStorage里恢复,用户信息在App.vue的onMounted里调一次接口拉回来,这个过程对用户是无感知的。对比一下Vuex的写法,少了mutation的样板代码之后,整个store的阅读体验和写代码的顺畅度都是明显提升的。

2.4 组件通信方案的选择

组件通信选对方案,能让代码优雅很多。props向下传、emit向上传是基础,但在交易系统里有两个场景我建议用provide/inject来处理,比层层传prop省太多事。

第一个场景是登录状态的全局传递。Layout组件在setup里通过provide注入userStore,子组件商品列表、导航栏、个人中心都能直接读取,不需要每一层都接收一个userInfo的prop。第二个场景是通用弹窗组件的控制,比如商品删除确认弹窗、订单取消确认框,父组件provide一个openConfirm方法,子组件inject后直接用,这种“方法注入”比props传函数然后emit回调要清爽。

页面上大量商品卡片、订单列表项这类数据展示组件,建议props只传必要的数据对象,不要在props里传方法。方法通过emit上抛到父组件统一处理,保持单向数据流,后续接到后端复杂逻辑时,调试链路会清晰很多。我还习惯给这类组件单独抽一个状态标签子组件,比如订单状态用不同颜色的tag展示,会让页面层次感好看很多。

3. 实操过程:前端核心模块从0到1

3.1 登录注册与用户体系搭建

登录模块看起来简单,但它是整个系统的入口,认证流程设计不好后面全乱。前端需要做的事包括:登录表单校验、调用登录接口、存储token、跳转回原页面。我用的是token方案,JWT或者简单token都可以,后端返回token后在本地存储一份,每次请求带上,后端的拦截器负责校验登录态。

登录成功后跳回来源页面这个细节很多人忽略。用户浏览商品详情页时登录过期,被重定向到登录页,登录完直接跳回首页显然很蠢。我的做法是在路由守卫里记住目标路由,登录成功后再跳过去:

router.beforeEach((to, from, next) => { const userStore = useUserStore() if (to.meta.requiresAuth && !userStore.isLoggedIn) { next({ path: '/login', query: { redirect: to.fullPath } }) } else { next() } })

注册页面的设计上,除了学号和密码之外,我还建议带一个院系选择下拉框,虽然不算核心功能,但是对后端的用户数据统计分析有帮助,也能让审核员在后台看到更完整的用户信息。表单校验这块用Element Plus自带的rules就够用了,正则校验学号格式、手机号格式,密码长度设置在6到20位之间,前端校验只是第一道防线,后端接口必须有同样的校验逻辑。

3.2 商品发布与图片上传实现

商品发布是二手交易系统的核心交互场景,表单字段至少要包括:标题、描述、分类、价格、原价(可选)、成色、交易方式、图片。前端用Form组件加rules做校验,标题限制20字以内,超过就不让提交,这是为了列表展示时的体验。描述建议做成纯文本区域,不要引入富文本编辑器,二手商品描述普遍不长,富文本的复杂度和安全风险都划不来。

图片上传这块有几个实际细节要处理好。第一个是一次连续上传多张图片,而不是让用户一张一张传。我用el-upload的file-list配合v-model绑定图片URL数组,上传成功后往数组里push,删除时同步从数组中移除。第二个是图片压缩,手机端拍的照片动不动好几兆,直接传既慢又占服务器空间。方案是在上传前用canvas压缩一下,长边控制在1280px,质量调到0.8,体积能降下来80%以上,肉眼看起来跟原图几乎没差别。第三是为每张图片生成一个本地临时ID,用于前端预览,上传成功后再替换成服务器返回的URL,避免上传过程中显示空白。

发布接口的返回机制也很讲究。后端要设计成“提交后进入待审核状态”,而不是直接上架。学生用户发布的商品可能包含违规内容,需要一个审核岗。前端发布成功后的跳转页面,我建议直接带到“我的发布”列表,并且清晰标注“审核中”状态,让用户知道自己的操作有没有被系统接收。

3.3 商品列表、搜索与筛选

商品列表是整个系统流量最大的页面,性能和体验要重点打磨。搜索区采用“关键词 + 分类 + 价格区间”三个维度,关键词走商品标题和描述模糊匹配,分类是精确筛选,价格区间可以是两个输入框也可以是一个Range组件。筛选后的排序支持最新发布、价格从低到高、价格从高到低三种,默认按发布时间倒序。

列表页的分页设计上,因为商品数量一般不会太大,后端可以做简单的分页或者更轻量的滚动加载。滚动加载更符合用户浏览习惯,但实现复杂度稍高一点,需要处理好滚动容器的监听和防抖。我建议做分页为主,因为毕设文档里写清楚PageHelper或MyBatis-Plus的分页逻辑比滚动加载更容易体现后端功底。

卡片组件的设计上,每个商品卡片用GoodsCard.vue统一渲染,展示第一张图片、标题、价格、成色、发布时间。点击卡片跳转到详情页,跳转方式用RouterLink。价格文字的样式要突出,红色加粗是二手交易平台的标配,原价用删除线展示,品牌感和信息层级都靠这些细节撑起来。

详情页还有一个关键点:浏览量的统计。每次进入详情页时调用一次浏览量加1的接口,这个数据在后台上可以看到,也可以作为排序的一个选项。技术上很简单,但设计文档里有这个细节会让系统显得完整不少。

3.4 订单流程与状态管理

订单模块是校验系统全面性的点。二手交易和电商还不完全一样,它会多一个“线下交付确认”的环节。我设计的订单状态机是:待付款 → 待确认 → 已完成,中间穿插已取消。买家下单时展示商品信息、卖家信息、付款金额,点击“确认下单”后订单生成并进入待付款状态;付款后订单进入待确认;卖家在“我的卖出”里看到待确认订单,点击确认完成按钮,订单关闭;买家如果暂不付款,可以取消订单。

前端用状态字符串来标识每个阶段,但不要直接拿这个字符串去显示,而是通过计算属性映射成文本和标签颜色。比如:

const statusMap = { pending_payment: { text: '待付款', type: 'warning' }, pending_confirm: { text: '待确认', type: 'primary' }, completed: { text: '已完成', type: 'success' }, cancelled: { text: '已取消', type: 'info' } }

低代码项目里很多人喜欢把状态写成数字0、1、2,但这个可读性太差,前后端调试的时候满屏数字很容易看错。字符串状态是接口层的约定,前端做映射表,后端的枚举类对应同一组字符串。这样一个后端开发者和前端开发者聊天的时候,说的是同一个词,而不是去对“2的含义是什么”。

订单列表要分“我买到的”和“我卖出的”两个Tab,分别调用不同的接口,展示不同的操作按钮。我买到的里,待付款可以取消或去付款;我卖出的里,待确认可以确认完成。交易完成后,双方可以互相评价,这套机制也可以做,但只做最基础的评分,不引入长文本评价,避免整个系统复杂度失控。

3.5 后台数据统计与审核管理

后台管理模块是校园系统里容易被低估的部分。很多同学把后台当成几个表格页面随便写写,结果答辩时被问一句“后台的审核流程怎么设计”就哑了。前台的每一件上架商品,后台都要能下架;每一个注册用户,后台都要能禁用;每一条订单,后台都要能查到详情。这是交易系统的安全底线。

统计部分我推荐加一个图表页,用ECharts或者轻量一点的图表库展示近一周发布量、成交量、分类占比。不用做得特别高级,两张图足矣。图表数据通过一个统计接口返回,后端用分组查询就能搞定。这个页面在答辩演示时很加印象分,能让评审老师一眼看到系统收集了数据并且做了可视化展示,而不只是增删改查。

后台前端我会复用一套同款布局,左侧菜单:商品管理、订单管理、用户管理、数据统计。权限上用简单的角色字段来判断,user表的role字段区分普通用户和管理员,前端通过Vue Router的meta字段做动态路由或按钮级权限控制。

4. 工程化配置与前后端联调细节

4.1 Vite配置与开发环境代理

创建项目时我习惯直接用npm create vite@latest选择vue模板,比手动配置webpack省太多事。生成后第一个要改的就是vite.config.js,这里有两个核心配置:alias路径别名和开发环境代理。

// vite.config.js import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import path from 'path' export default defineConfig({ plugins: [vue()], resolve: { alias: { '@': path.resolve(__dirname, 'src') } }, server: { port: 5173, proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true } } }, build: { chunkSizeWarningLimit: 2000, rollupOptions: { output: { manualChunks: { vendor: ['vue', 'vue-router', 'pinia', 'axios'], element: ['element-plus'] } } } } })

代理配置务必在写接口前就搞定,否则前后端联调时每个请求都要跨域调试,浪费时间不说,还会让你误以为CORS问题很简单。前端请求地址统一写成/api开头,代理把/api转发到后端服务端口,生产环境上线时再让Nginx做同样的跳转。开发环境手写完整地址会造成大量修改,不要偷懒。

上面这段配置里我还加了构建时的manualChunks分包,把第三方库单独拆出来,这也是性能优化里比较关键的一步。

4.2 Axios二次封装与拦截器

Axios在项目里最好封装成一个统一的实例,而不是在组件里直接用axios.post。为什么?因为统一封装能管好token注入、错误提示和加载状态三件事。我的封装思路如下:

// utils/request.js import axios from 'axios' import { ElMessage } from 'element-plus' const request = axios.create({ baseURL: '/api', timeout: 10000 }) request.interceptors.request.use(config => { const userStore = useUserStore() if (userStore.token) { config.headers.Authorization = `Bearer ${userStore.token}` } return config }) request.interceptors.response.use( response => { const res = response.data if (res.code !== 200) { ElMessage.error(res.msg || '请求失败') return Promise.reject(new Error(res.msg)) } return res.data }, error => { if (error.response?.status === 401) { // 登录失效,跳转登录页 } ElMessage.error(error.message || '网络异常') return Promise.reject(error) } )

拦截器里最重要的设计是响应拦截器统一解包。后端返回的JSON格式统一为{ code: 200, msg: 'success', data: {...} },拦截器里判断code,非200就弹错误提示,正常就直接返回data字段。这样前端业务代码拿到的是干净的data,不需要每调用一个接口都重复判断一次code和弹错误。

Token过期处理也是个实际点。响应拦截器收到401时清掉本地token,跳转登录页。这个逻辑一定要写,不然系统上线后用户停留久了会出现“页面还在,操作时报错”的尴尬场景。

4.3 路由懒加载与打包部署

路由懒加载是Vue3项目里默认的操作,Vue Router的component参数直接写成箭头函数动态import:

const routes = [ { path: '/', component: () => import('@/layout/Index.vue'), children: [ { path: '', name: 'Home', component: () => import('@/views/home/Home.vue') } ] } ]

不要小看这个细节,不写懒加载的话,首屏会把所有页面组件全都打包成一个巨大的JS文件,加载速度感人。加上懒加载后,每个页面单独成文件,浏览器只下载首屏需要的部分,体验差距极其明显。

部署时托管到Nginx是最常见的方案,Vue Router要记得用history模式,那么Nginx需要配置try_files。一个最简配置如下:

server { listen 80; server_name your-domain.com; root /var/www/dist; index index.html; location / { try_files $uri $uri/ /index.html; } location /api { proxy_pass http://127.0.0.1:8080; } }

这个配置解决了两个问题:浏览器直接访问子路径时不会404;开发期的/api前缀搬到服务器上也同样正确转发到后端服务。跨域不再需要后端同学去配CORS,生产环境也不会留下跨域隐患。

5. 常见问题与排查技巧实录

5.1 响应式数据离职:数据和视图不同步

这类问题我在给人看项目时遇到最多,现象是接口返回数据后,页面上没有渲染出列表,控制台一查数据其实已经有了。十有八九是reactive的“整体赋值”问题。

一个典型的错误写法是:

const list = reactive([]) list = res.data // 直接替换整个数组,响应式丢失

正确的做法是用ref声明列表,或者用list.splice(0, list.length, ...res.data)这样更新数组内容。在我的项目里商品列表我统一用ref来管理,简单直接,不容易踩坑。其他容易翻车的地方还包括:直接给reactive对象动态加属性又会涉及新增属性的响应式问题,这个在Vue3里已经解决了,但如果你的代码还保持着Vue2时代的防御式写法,反而会绕晕了自己。

5.2 组件渲染异常:v-for中的key要用正确值

还有一个高频报错场景是控制台警告“Duplicate keys detected”,根源是列表的key用的是index。在商品列表含搜索排序时,用index做key会造成严重问题,列表项状态复用错乱,比如一个商品的“收藏”状态串到了另一行。固定商品ID是天然的唯一key,但注意不要用随机数或时间戳,否则刷新后key漂移,组件状态全部重置。

Element Plus的表格组件也一样,涉及el-table-column时,最好在后端返回的数据里保证有一个稳定字段当key。做订单列表时我吃过这个亏,当时用订单创建时间当key,结果用户在两秒内下了两单,页面渲染乱套了。换成订单ID问题立刻消失。

5.3 接口请求失败:跨域和代理要分清

很多初学者搞不清“跨域”和“代理”的区别,调试前端页面时看到Network面板里一个红色失败请求就大喊“跨域了”,其实未必。开Vite开发服务器后,浏览器请求的是5173端口的页面,但接口目标是8080,这时候如果axios直接发8080请求,跨域确实存在;但我配置了proxy之后,前端请求相对路径/api/goods,Vite开发服务器会自动转发到8080,浏览器里看到的是同源请求,根本不涉及跨域。

如果配好代理后接口还是失败,优先看Vite控制台有没有报代理错误,或者后端是否在正确端口上跑起来。生产模式下Nginx反向代理可能配置了限制请求体大小,图片上传失败时优先看nginx的client_max_body_size配置,默认1M会让多图上传直接挂掉。

5.4 构建部署后页面空白

本地开发一切正常,npm run build后扔到服务器打开一片空白,这个场景我见了不下五次。基本三个原因:路由模式导致刷新404、base路径不对、静态资源请求路径带不了前缀。把Vue Router改成history模式,再做Nginx的try_files,绝大多数404问题能解决;如果你部署在子路径下,Vite的base配置要改成子路径名称,然后资源路径才会正确拼接。如果你把dist直接放在服务器根目录,那保持默认的base就完全OK。

Element Plus按需引入时,如果build后样式丢失,检查是否装了unplugin-auto-import和unplugin-vue-components,并且vite.config.js的plugins里正确注册了这两个插件。这个配置细节非常容易漏,忘了配就会出现“功能正常,样式全丢”的诡异现象。

6. 优化扩展与个人经验总结

到这里,一个基于Vue3的校园二手商品交易系统的核心内容已经全部跑通了。从需求拆解、技术选型、前端架构,到关键模块实现和联调部署,再到常见问题的排查,整个过程里我最深的体会是:前端技术栈的新旧其实不是项目成败的关键,你对业务逻辑的理解深度和代码组织能力才是。

后续想在这个基础上继续扩展,有两条路很值得做。一是接入真正的支付功能,把虚拟的“确认付款”换成微信或支付宝的扫码支付,订单状态机和回调处理逻辑会复杂不少,但对系统完整性是质变。二是加上消息私信模块,让买卖双方可以在站内沟通交易时间和地点,这对校园场景的体验提升非常明显。技术上都是在现有架构上加模块,不会伤筋动骨。

最后分享一个小技巧:把所有的业务状态码、接口返回码、错误提示文案都集中定义在一个常量文件里,前后端共同维护一份。这个习惯在开发中期联调时能帮你节约大量沟通成本。我在这个项目里把订单状态、商品成色、用户角色都做成了前端常量映射表,后端的枚举值和它一一对应,排查问题时只要对着常量表看,定位速度翻倍。

如果你正在做类似的项目,建议先按照本文的架构把骨架搭起来,跑通主流程之后再做细节打磨。遇到“页面不更新”、“接口跨域”、“打包空白”这类问题,回头看看第5节,大概率能找到答案。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询