我的第一个开源项目:SpringCloud电商前端Vue实战
这篇文章记录了作者开发第一个开源项目——基于SpringCloud的电商管理系统前端的心路历程。文章详细描述了从环境搭建(Node.js中文路径问题、Vue CLI版本兼容)到核心功能开发(路由设计、Axios封装、品牌管理模块、SKU配置)的全过程,分享了技术难点与解决方案。作者通过实践掌握了Vue+Element UI的企业级开发技能,最终完成了包含商品管理、权限控制等功能的电商后台系统。文章
我的第一个开源项目:SpringCloud电商前端Vue实战
作为一名刚接触企业级开发的程序员,我始终记得第一次提交代码时的紧张——凌晨两点的屏幕前,手指悬在回车键上迟迟不敢落下。而我的第一个开源项目——基于SpringCloud的电商管理系统前端,就藏着无数个这样的瞬间。从环境搭建时的手足无措,到功能跑通时的狂喜,每一行代码都刻着成长的痕迹。
项目缘起:为什么选择电商系统?
选择电商系统作为第一个开源项目,源于两个考量:一是电商场景涵盖了企业开发的核心需求(用户管理、商品管理、权限控制等),能全面锻炼技术能力;二是前端作为用户直接接触的层面,视觉与交互的成就感更直观,适合作为开源入门的切入点。
我们的目标是开发一个完整的电商管理后台,包含品牌管理、商品分类、SKU配置、用户权限等模块,前端采用Vue+Element UI实现,后端基于SpringCloud微服务架构。而我主要负责前端部分的开发,这也是我第一次系统性地使用Vue生态。
踩坑第一步:环境搭建的"连环坑"
环境搭建是开源项目的第一道门槛,而我差点栽在这一步。
最初按照文档安装Node.js时,误将安装路径改成了中文目录,导致后续cnpm始终报错。排查两小时后才发现,Node.js对中文路径的兼容性问题会导致依赖包解析失败。重新安装到默认路径(C:\Program Files\nodejs)后,才算解决了第一个问题。
# 全局安装cnpm时的正确命令(阿里镜像加速)
npm install cnpm -g --registry=https://registry.npmmirror.com
安装Vue CLI时,又遇到了版本兼容问题。最初安装的4.x版本与项目依赖冲突,报错"vue-cli-service: command not found"。查了无数issue后才知道,项目文档中推荐的3.10.0版本是经过验证的"无坑版",最终通过指定版本解决:
# 安装指定版本的Vue CLI
cnpm install -g @vue/cli@3.10.0
创建项目时,我犯了一个低级错误——给项目名加了大写字母(如"ShopAdmin"),导致Vue CLI直接报错"Project name can’t contain uppercase letters"。原来Vue项目名必须小写,这是为了兼容跨平台文件系统的命名规范。
核心功能开发:从"能跑"到"好用"
路由设计:单页应用的"导航图"
Vue的路由设计是前端架构的核心。最初我直接使用默认路由配置,导致所有页面都挤在一个窗口里。后来才理解,电商后台需要"主页面+子页面"的层级结构:左侧导航栏固定,右侧内容区动态加载组件。
通过嵌套路由实现这一效果:主路由加载布局组件(包含导航栏和内容区),子路由对应具体功能页面(如品牌管理、商品列表)。
// src/router/index.js
const routes = [
{
path: '/',
name: 'Index',
component: () => import('@/views'), // 主布局组件
children: [
{
path: '/brand', // 品牌管理子路由
name: 'BrandIndex',
component: () => import('@/views/brand')
},
{
path: '/category', // 分类管理子路由
name: 'CategoryIndex',
component: () => import('@/views/category')
}
]
}
]
异步请求:Axios封装的"血泪史"
最初直接在组件中写Axios请求,导致代码重复率极高。比如品牌列表的查询,每个组件都要写一遍axios.get(...),一旦接口地址变更,所有组件都要修改。
后来参考开源项目的最佳实践,封装了全局请求方法:
// src/plugins/axios.js
Vue.prototype.request = (url, method, params, callback) => {
// 请求前显示加载动画
const txLoading = Loading.service({ text: '拼命加载中' });
_axios.request({
url: url,
method: method,
// get请求用params,post用formData
[method === 'get' ? 'params' : 'data']: params
}).then(response => {
callback(response.data);
}).finally(() => {
txLoading.close(); // 无论成功失败都关闭加载动画
});
};
// 封装get和post简化调用
Vue.prototype.get = (url, params, callback) => {
request(url, 'get', params, callback);
};
Vue.prototype.post = (url, params, callback) => {
request(url, 'post', params, callback);
};
封装后,组件中调用变得简洁:
// 品牌列表查询
this.get('/pms-brand/list', { pageNo: 1 }, response => {
this.tableData = response.records;
});
但新的问题来了:跨域。前端80端口访问后端8081端口时,浏览器报"CORS policy"错误。最终在后端配置跨域过滤器解决:
// 后端跨域配置
@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("*"); // 允许所有域名
config.addAllowedMethod("*"); // 允许所有请求方法
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
品牌管理模块:增删改查的"闭环实践"
品牌管理是第一个完整实现的模块,包含列表查询、新增、修改、删除功能,也是我第一次体会到"功能跑通"的成就感。
列表页使用Element UI的el-table组件,通过v-for循环渲染数据。但最初图片无法显示,排查后发现是图片路径拼接问题——后端返回的是图片名称,需要拼接MinIO服务器地址:
<!-- 品牌列表中的图片显示 -->
<el-table-column label="图片" width="260px">
<template slot-scope="scope">
<el-image
:src="img(scope.row.img)"
style="width: 100px; height: 80px"
fit="contain">
</el-image>
</template>
</el-table-column>
// main.js中定义全局图片路径拼接方法
Vue.prototype.img = (url) => {
return 'http://192.168.149.131:9000/images/' + url;
};
新增功能的弹窗表单中,我遇到了"表单验证不生效"的问题。原来Element UI的el-form需要通过prop属性与rules对应:
<el-form :model="form" :rules="rules" ref="txform">
<el-form-item label="品牌名" prop="name">
<el-input v-model="form.name"></el-input>
</el-form-item>
</el-form>
<script>
export default {
data() {
return {
rules: {
name: [
{ required: true, message: '请输入品牌名', trigger: 'blur' }
]
}
}
}
}
</script>
商品SKU配置:最复杂的"动态组合"
SKU(最小库存单位)是电商系统的核心难点——用户需要选择颜色、尺码等属性,系统自动生成组合并配置库存。
最初直接用el-checkbox-group实现,但属性值动态添加时出现了"勾选状态不更新"的问题。最终通过给每个属性值绑定唯一key,并在数据更新时强制刷新组件解决:
<el-form-item label="颜色">
<el-checkbox-group v-model="item.value">
<el-checkbox
v-for="color in item.inputList.split(',')"
:key="color"
:label="color">
</el-checkbox>
</el-checkbox-group>
</el-form-item>
为了实现"动态添加属性值"(如新增一种颜色),我在组件中添加了输入框和"添加"按钮,点击后将新值追加到inputList:
addSku(item) {
if (item.addvalue) {
item.inputList += ',' + item.addvalue; // 追加新值
item.addvalue = ''; // 清空输入框
}
}
上线与开源:从"本地跑通"到"公开可用"
项目开发到第3个月,终于完成了核心功能。但上线前的部署又给了我"致命一击"——本地运行正常的代码,打包后图片全部失效。
排查发现,Vue打包时会将静态资源路径转为相对路径,而图片路径是硬编码的绝对路径。通过修改vue.config.js中的publicPath配置解决:
// vue.config.js
module.exports = {
publicPath: './' // 打包时使用相对路径
};
最终,我在GitCode上创建了仓库,提交了第一版代码。看着git log里的提交记录,从"fix: 跨域问题"到"feat: 完成SKU模块",突然意识到:开源的意义不仅是分享代码,更是记录成长的轨迹。
结语:开源给我的三个礼物
这个项目让我收获了远超技术本身的成长:
- 解决问题的耐心:从环境搭建到跨域调试,每个问题都是"百度3小时,改码5分钟",但正是这些经历让我学会了拆解问题。
- 代码的洁癖:为了让开源代码可读,我强迫自己写注释、拆组件,代码风格逐渐规范。
- 分享的勇气:最初怕代码写得烂被嘲笑,但看到有人Star并提Issue时,才明白开源的本质是互助。
如今再看这个项目,代码里满是"新手痕迹":冗余的判断、未优化的渲染。但我舍不得重构——这些不完美,才是最真实的成长印记。
如果你也是开源新手,不妨从一个小模块开始。毕竟,每个大神都曾是"提交代码会手抖"的萌新。
(项目地址:https://gitee.com/xiao-yezi/spring-cloud-project,欢迎Star和PR!)
更多推荐



所有评论(0)