从“Hello Vue”到上线:我的Vue.js入门与实战之旅
引言:为什么选择分享这段经历?

我第一次接触到 Vue.js 的时候,其实是抱着试试看的心态。当时手头有一个内部管理系统的小项目需要快速搭建原型,原本考虑用 React,但团队成员对 Vue 的熟悉度更高,于是决定试一把。
没想到这一试,让我彻底爱上了这个框架。它轻量、易上手、生态也足够成熟,而且社区活跃,在踩坑的路上从来不会孤单。更重要的是,它真的能帮你把想法快速落地。
今天我想通过自己的实际工作经历,和大家一起从零开始,走进 Vue.js 的世界。这篇文章会围绕一个真实的小项目展开——我们如何从零搭建了一个用户管理模块,并最终成功上线。
希望你在读完之后,也能有信心亲手写一个属于自己的 Vue 应用。
一、项目背景与挑战:一个简单的用户管理后台

我们的项目目标其实很简单:为公司内部的 HR 部门搭建一个用户信息管理的后台系统。主要功能包括:
- 用户列表展示(姓名、工号、部门)
- 支持根据工号搜索
- 可点击查看详情页
- 权限控制(只有管理员能看到操作按钮)
听起来是不是挺简单的?是的,但也有一些隐藏的痛点在等待着我们。
初期挑战:开发周期紧张 + 团队协作压力大
由于是新组建的小组,前端部分由我一个人负责,时间只有短短三周,任务包括组件设计、路由配置、状态管理和 API 联调。我之前做过一些 jQuery 和原生 JS 的项目,但在现代框架方面经验不足。
React 虽然更流行,但我们团队中有人用过 Vue,所以选它可以减少沟通成本。而且 Vue 上手快,文档友好,非常适合这种短期项目。
二、解决方案:为什么选择 Vue?如何设计架构?

技术栈选择
项目技术栈如下:
- Vue.js(使用的是 Vue 3 + Composition API)
- Vite(作为构建工具,比 Webpack 快很多)
- Element Plus(UI 组件库,适配 Vue 3)
- Pinia(替代 Vuex 的状态管理方案)
- Vue Router(处理页面跳转)
- Axios(封装网络请求)
- ESLint + Prettier(代码规范)
整个架构采用组件化开发思想,按照功能划分模块,遵循单一职责原则。
三、开发实践:从零搭建第一个组件

Step 1:初始化项目
我用 Vite 创建了项目:
npm create vite@latest vue-user-dashboard --template vue-ts
cd vue-user-dashboard
npm install
npm run dev
简单几步,就能看到 Vue 默认的页面了!
小贴士:使用
vue-ts模板可以启用 TypeScript,如果你不熟悉 TS 也可以直接选vue,效果一样。
Step 2:创建第一个组件 —— 用户列表
我先新建了一个 components/UserList.vue 文件,结构如下:
<template>
<el-table :data="users" style="width: 100%">
<el-table-column prop="name" label="姓名" />
<el-table-column prop="id" label="工号" />
<el-table-column prop="department" label="部门" />
</el-table>
</template>

<script setup>
import { ref } from 'vue';
const users = ref([
{ name: '张三', id: 'U001', department: '产品部' },
{ name: '李四', id: 'U002', department: '研发部' }
]);
</script>
然后在首页 App.vue 中引入并使用这个组件。
看起来很顺利?没错,但这只是个静态数据版本。接下来要让它从接口获取真正的数据。
四、关键功能实现:从静态展示到动态交互
实现搜索功能
我们在表格上方加一个搜索框:
<template>
<div>
<el-input v-model="searchKey" placeholder="输入工号进行搜索" />
<el-button @click="handleSearch">查询</el-button>
</div>
<!-- 表格部分省略 -->
</template>
<script setup>
import { ref } from 'vue';
const searchKey = ref('');
const users = ref([]);
const filteredUsers = ref([]);
function handleSearch() {
if (!searchKey.value) {
filteredUsers.value = users.value;
return;
}
filteredUsers.value = users.value.filter(user =>
user.id.includes(searchKey.value)
);
}
</script>
这里用到了 Vue 的双向绑定 v-model 和响应式数据 ref。
小插曲:一开始我以为
ref是用来做 DOM 操作的,后来才发现它主要是为了让数据具备响应性。真是误打误撞地学会了基本原理 😅。
五、API 联调:用 Axios 获取真实数据
我们将请求封装在一个服务文件里:
// services/userService.js
import axios from 'axios';
const apiClient = axios.create({
baseURL: 'https://api.example.com/users',
});
export default {
getAllUsers() {
return apiClient.get('/');
},
getUserById(id) {
return apiClient.get(`/${id}`);
}
};
然后在组件中调用:
import userService from '../services/userService';
onMounted(async () => {
const res = await userService.getAllUsers();
users.value = res.data;
filteredUsers.value = res.data;
});
这样我们就把真实的数据拉下来了。
六、路由配置与详情页跳转
我们想让用户点击某一行时跳转到详情页。这时候就需要用到 Vue Router。
安装:
npm install vue-router@4
然后创建 router/index.js:
import { createRouter, createWebHistory } from 'vue-router';
import UserDetails from '../views/UserDetails.vue';
const routes = [
{
path: '/user/:id',
name: 'UserDetails',
component: UserDetails
}
];
const router = createRouter({
history: createWebHistory(),
routes
});
export default router;
在主入口文件 main.js 中挂载它即可。
现在回到用户列表组件中添加跳转:
<el-table-column label="操作">
<template #default="{ row }">
<el-button @click="$router.push(`/user/${row.id}`)">查看详情</el-button>
</template>
</el-table-column>
七、状态管理:从 ref 到 Pinia
随着项目越来越大,我发现只靠 ref 管理状态有些吃力。尤其是多个组件之间需要共享用户信息的时候,传递 props 非常麻烦。
于是我引入了 Pinia:
npm install pinia
在 store 中定义:
// stores/userStore.js
import { defineStore } from 'pinia';
export const useUserStore = defineStore('user', {
state: () => ({
selectedUser: null,
}),
});
然后在详情页组件中使用:
import { useUserStore } from '@/stores/userStore';
const userStore = useUserStore();
再也不用一层层传参啦!
八、实战踩坑:我在开发过程中遇到的问题
🧱 坑一:异步加载导致数据为空
一开始我没有在组件加载完成前就渲染列表,结果报错 Cannot read property 'name' of undefined。
解决方式是在模板中加上 v-if="users.length",或者使用可选链语法:
{{ user?.name }}
🧱 坑二:浏览器兼容性问题
虽然大多数现代浏览器都支持 Vue 3,但在某些老的设备上会出现白屏问题。我们排查发现是 Vite 构建后的 ES module 无法被识别。
最终解决方法是在 vite.config.js 中设置:
build: {
target: 'es2015'
}
同时建议使用 Babel 插件来进一步兼容。
🧱 坑三:Pinia 在 SSR 场景下的副作用
在后续尝试接入 Nuxt.js 实现 SSR 时,Pinia 的默认 setup 方式会在服务端抛出错误。需要额外配置 defineStore 为组合式函数方式才能解决。
九、项目上线:性能优化和部署
项目完成后,我们做了几个优化点:
✅ 使用 Element Plus 按需加载
避免一次性引入所有组件,提升首屏速度。
✅ 图片懒加载 + 资源压缩
对于头像等图片资源,我们使用了 Vue 的 v-lazy 指令。
✅ 启用 Gzip 压缩
Nginx 后端开启 Gzip,JS 包体积减少约 60%。
✅ 部署到 Nginx 服务器
用 vite build 打包之后上传到服务器,配合 history 模式的路由重定向配置即可访问。
上线之后性能测试良好,首次内容绘制(FCP)控制在 2 秒内,用户体验不错。
十、总结与建议:给初学者的一些建议
✅ 推荐学习路径
- 学好 HTML/CSS/JS 基础
- 先掌握 Vue 核心概念(响应式、指令、生命周期)
- 尝试做一个小项目练手(比如 todo list)
- 加入状态管理工具(Pinia/Vuex)
- 进阶学习 Vue Router、Composition API、Teleport 等高级特性
- 熟悉工程化工具如 Vite/Webpack
- 学习如何优化性能和调试
💡 我的心得体会
- Vue 不仅仅是一个框架,而是一种开发思维。它教会我如何拆解复杂问题,如何组织代码结构。
- 不要怕踩坑。每一个 bug 都是一次成长的机会。
- 保持好奇心和动手能力。技术更新很快,但动手写出来才是自己的。
结语:一起写下去吧,属于你的 Vue 项目
这篇文章记录了我从零到上线的第一个 Vue 项目,也希望它能成为你踏上 Vue 开发之路的一个起点。
你可以试着复制文中的代码片段,运行一下,看看那个小小的表格是不是活了起来。或许下一次的项目迭代,你就能做出一个完整的业务模块。
技术这条路很长,但只要一步一步走下去,终能到达你想去的地方。
如果你也有类似的经历,欢迎留言交流!我们一起成长。🌟
文章字数统计:约 3571 字

评论 0