我的第一个开源项目:SpringCloud电商前端Vue实战
我的第一个开源项目: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 {@Beanpublic 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时,才明白开源的本质是互助。
如今再看这个项目,代码里满是"新手痕迹":冗余的判断、未优化的渲染。但我舍不得重构——这些不完美,才是最真实的成长印记。
如果你也是开源新手,不妨从一个小模块开始。毕竟,每个大神都曾是"提交代码会手抖"的萌新。
SpringCloud电商项目开发完整流程
(项目地址:https://gitee.com/xiao-yezi/spring-cloud-project,欢迎Star和PR!)