简介:Vue.js 是当前流行的前端框架之一,这份“VUE前端小例子”资源面向刚开始接触 Vue 的开发者,通过一个简洁的资产管理应用帮助理解 Vue 实例、数据绑定、计算属性、组件化、模板语法等核心概念,并顺带涉及路由与状态管理的初步用法,适合作为入门实践或课程设计参考。资源压缩包仅 45KB,共包含 39 个文件,其中 15 个 js 脚本负责逻辑与构建配置,9 个 vue 组件展示组件化写法,另有 JSON 配置、PNG 图片及项目说明等,结构完整,便于对照学习。目前该资源已有 4209 人学习下载。解开压缩包后,读者可以查看 webpack 构建配置、router 路由设置、Vue 组件目录以及静态资源组织方式,对理解一个真实 Vue 工程的基本骨架很有帮助;同时代码中的布局和响应式处理也能为前端样式实现提供借鉴,整体上是一份麻雀虽小、五脏俱全的入门级示例。 直接开工,这篇博文就当是我这个老前端,最近带新人重构一个内部管理系统时,顺手整理出来的一份实战笔记。项目不大,但五脏俱全,从环境搭建到打包部署,把Vue开发里那些高频的坑和技巧都串起来了。给正在学Vue的、准备面试的、或者刚接手项目的朋友做个参考。
1. 项目整体设计与思路拆解
1.1 为什么是Vue,以及项目定位
这次要做的“VUE前端小例子”,其实是一个轻量级的后台管理系统前端。选Vue不是因为它比React高一等,纯粹是务实:团队现有成员最熟的就是Vue,而且项目本身是配合Spring Boot做前后端分离,Vue的生态(路由、状态管理、UI库)能让我们用最小的成本把页面堆出来。
这个例子的核心诉求有三点:一是把登录鉴权跑通(账号密码登录 + 路由守卫);二是把最常见的列表增删改查做透;三是把文件上传、视频播放、消息推送这些“高频但容易翻车”的功能,做成可以复用的模块。对新手来说,跟着这个例子走一遍,基本就等于把Vue开发的主干线摸清了。
1.2 选项式API和组合式API怎么选
盯着这个项目,我一开始就面临一个选择题:用选项式(Options API)还是组合式(Composition API)?
我的建议是:新项目直接用组合式,老项目维护用选项式也完全没问题。组合式API最大的优势是把同一个业务逻辑的代码收拢在一起,不用再“数据在data里、方法在methods里”来回跳。比如做一个用户列表,搜索条件、列表数据、加载方法可以全部放到一个setup里的区域块,改动起来非常顺手。对于团队协作,如果项目里既有老手又有新人,组合式API配合<script setup>写法,代码量能减少三分之一,肉眼可见地清爽。
不过这不是说选项式一无是处。如果你的业务页面非常简单,纯粹是表单展示,选项式的结构化反而更直观。我自己的习惯是:页面复杂度高、逻辑需要复用的选组合式;简单静态页面用选项式也凑合。两种写法都熟,面试的时候才不会露怯。
2. 核心细节解析与实操要点
2.1 环境安装与脚手架搭建
这一步是很多新手第一道坎儿。先说结论:请务必使用nvm管理Node版本,不要直接在官网下载最新的Node用到底。我见过太多人因为Node版本过高导致依赖安装失败,或者node-sass编译不过去。推荐的做法是装nvm,然后安装一个稳定的LTS版本(比如16.x或18.x),再用npm或pnpm全局安装@vue/cli或直接使用create-vue创建项目。
实操命令很简单:
# 用nvm安装并切换Node版本 nvm install 18.18.0 nvm use 18.18.0 # 创建Vue3项目(推荐Vite驱动) npm create vue@latest my-demo # 或者用Vue CLI(适合老项目维护) npm install -g @vue/cli vue create my-demo创建过程中会有交互式选项,比如是否安装路由、Pinia、ESLint等。新手建议全选Yes,省得后面手动补。一个小提醒:项目名别用中文,也别用下划线开头的名字,否则npm依赖树解析会有莫名其妙的坑。
2.2 路由配置与参数传递
路由是Vue项目的骨架。我见过不少初学者的代码,router/index.js里堆了两三百行,没有任何嵌套和懒加载。这里分享一个基础但规范的做法:
- 页面级组件用懒加载(
component: () => import('@/views/xxx.vue')),减少首屏白屏时间。 - 区分“布局路由”和“页面路由”,布局路由套一层
Layout组件,子路由嵌套在children里。 - 路由参数务必区分
query和params:query传参适合搜索条件(URL里能看到,刷新不丢);params传参适合详情页ID(配合name跳转,刷新可能丢失,要谨慎)。
// 路由传参示例 // 跳转 router.push({ path: '/detail', query: { id: 123 } }) router.push({ name: 'detail', params: { id: 123 } }) // 接收 const route = useRoute() route.query.id // 方式一 route.params.id // 方式二一个容易忽视的坑是:用params传参时,如果页面刷新,参数会变成undefined。真正做详情页,更稳妥的方案是把参数放在query里,或者存到Pinia/本地缓存里。这个细节在做“列表跳详情”功能时尤其重要。
2.3 组合式API核心:ref与reactive
组合式API里最常用的就是ref和reactive。我的经验是:基础类型和数组用ref,深层对象用reactive,但别忘了reactive的“响应式陷阱”——解构赋值会让数据丢失响应性。这就好像你把一个插线板上的插头拔下来再插到别处,电虽然还是那个电,但原来的插座已经不通了。
举个例子:
// ref用法 const count = ref(0) const list = ref([]) count.value++ // 注意取value // reactive用法 const state = reactive({ name: '张三', age: 18 }) // 错误示范:解构后age就变成普通变量了 const { age } = state // 正确方式:使用toRefs const { age } = toRefs(state)我在实际项目中,更偏爱ref多一点,因为写起来统一,思考成本低。而且Vue官方也在向这个方向引导,ref的.value虽然啰嗦,但好处是语义明确,一看就知道是响应式数据。
3. 实操过程与核心环节实现
3.1 项目结构搭建与UI组件库引入
这次例子我选了Ant Design Vue作为UI组件库。原因很简单:组件全、文档清晰、后台管理系统最常见。安装方式:
npm install ant-design-vue@4.x引入方式有两种:全量引入和按需引入。日常开发,尤其是公司内部系统,全量引入问题不大,虽然包体积大一点,但省心。如果做对外C端项目,再用unplugin-vue-components做按需加载也不迟。别一开始就追求极致性能,反而把开发效率拖慢了。
项目结构我建议这样规划:
src/ ├── api/ # 接口请求 ├── assets/ # 静态资源 ├── components/ # 通用组件 ├── router/ # 路由配置 ├── store/ # 状态管理(Pinia) ├── utils/ # 工具函数 ├── views/ # 页面组件 ├── App.vue └── main.js这个结构不花哨,但足够清晰。新人接手能快速找到要改的文件,这就是好结构。
3.2 登录鉴权与路由守卫
登录是整个系统的入口,也是前后端联调的第一个环节。我用一个简单的token方案演示:
- 登录接口返回
token,存到sessionStorage和Pinia里。 - 路由守卫(
router.beforeEach)判断token是否存在,不存在则跳转登录页。 - 请求拦截器(axios)自动带上
Authorization头。
核心代码像这样:
// 路由守卫 router.beforeEach((to, from, next) => { const token = sessionStorage.getItem('token') if (to.path === '/login') { next() } else if (!token) { next('/login') } else { next() } })这里有一个非常关键的实践细节:路由守卫里不能只判断“有没有token”,还要考虑token过期的情况。最简单的处理是在axios响应拦截器里,遇到401状态码时清除本地token并强制跳转登录页。否则用户过一段时间再操作,会发现页面白屏或者一直报错,体验非常糟糕。
前后端分离的项目,登录接口通常由后端(Spring Boot)提供,前端只需要处理好CORS跨域问题。开发环境下,建议用Vite的代理配置,而不是在后端硬开跨域。
// vite.config.js 开发环境代理 server: { proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, '') } } }3.3 可视化配置:日历禁用与实时数据获取
项目里有个排班日历页面,需求是“当前月份之前的日期不可选”。这个点看着小,但特别能考察对组件库的熟悉程度。
Ant Design Vue的日历组件支持disabledDate回调,我们只需要写一个判断函数:
const disabledDate = (currentDate) => { // 只能选择当前月份及之后的时间 return currentDate && currentDate.startOf('day') < dayjs().startOf('day') }注意一定要用dayjs做日期比较,直接用new Date()比较可能会有时区或格式问题。
另外,系统里还有一个“通知推送”的模块,后端用的是SignalR(一种实时通信框架),前端要拿到推送数据,不能靠轮询,得建WebSocket连接。
// 前端连接SignalR import * as signalR from '@microsoft/signalr' const connection = new signalR.HubConnectionBuilder() .withUrl('/api/chatHub') .withAutomaticReconnect() .build() connection.on('ReceiveMessage', (message) => { // 收到消息,更新页面数据 messageList.value.push(message) }) connection.start().catch((err) => console.error('SignalR连接失败:', err))如果是纯前后端分离的WebSocket场景,前端浏览器原生new WebSocket(url)也够用,注意处理onmessage、onclose重连逻辑即可。我的经验是:能用现成SDK就别自己造轮子,但必须理解底层是WebSocket,否则出了问题都不知道从哪查。
3.4 性能优化:从JSON.stringify谈起
热词里有“json.stringify前端性能优化”,这个点让我特别有共鸣。很多同学在提交数据时喜欢这样写:
const formData = { name: '张三', age: 18, hobby: ['篮球', '吉他'] } axios.post('/api/user', JSON.stringify(formData))JSON.stringify本身是必要的,但优化点在于:对于大型列表或频繁调用的场景,重复执行JSON.stringify会阻塞主线程。比如一个实时搜索功能,用户每敲一个字母就发起请求,每次都把整个大对象序列化一遍,页面会卡顿明显。优化方案是:加上debounce(防抖),把多次触发合并成一次,同时用JSON.stringify缓存上一个请求的结果,如果数据没变化就不发请求。
另外一个更隐蔽的优化点:当你只需要提交表单里的某几个字段时,不要直接序列化整个大对象。先做一层解构或字段筛选,再序列化。这能减少传输体积,也能避免把一些不需要的字段(比如临时UI状态)提交给后端。
4. 常见问题与排查技巧实录
4.1 图片防盗链与本地加载难题
前面热词里有两个很实际的问题:“前端此图片未经允许不可引用怎么解决”和“本地加载vue打包好的项目”。
第一个问题,通常是后端返回的图片做了防盗链限制,前端直接引用时,请求头里带了Referer字段,被后端拒了。解决办法有几种:
- 后端在Nginx里配上图片的
Referer白名单。 - 后端把图片改为Base64或走接口代理返回。
- 前端用
<meta name="referrer" content="no-referrer">让请求不带Referer。
第二种方式比较灵活,但会增加服务器流量;第三种方式最省事,但有安全隐患,适合对安全要求不高的场景。
第二个问题,本地加载打包好的Vue项目,核心难点在于静态资源路径。默认情况下,Vite打包后资源路径是绝对路径/assets/xxx.js,如果你把dist文件夹直接用file://协议打开,会白屏。解决办法是改vite.config.js里的base:
// vite.config.js export default defineConfig({ base: './', // 改成相对路径 })改完之后重新打包,就能直接双击index.html本地预览了。如果是iOS的WebView加载本地打包文件,同理,只要确保WebView的URL指向index.html,且所有资源都是相对路径就能正常打开。但要注意:iOS的WKWebView对本地文件访问的沙盒限制比较多,建议用loadFileURL方法,而不是loadRequest。
4.2 大文件上传与Vue项目打包成exe
“前端使用worker上传大文件”这个话题,进阶开发者一定要懂。大文件上传的核心思路是切片上传:将大文件切成若干小块,分批次上传,最后后端合并。
用Web Worker做切片的好处是:切片和文件读取不阻塞主线程,页面不会卡死。我通常这样实现:
// 在Worker中执行切片 self.onmessage = async (e) => { const file = e.data.file const chunkSize = 2 * 1024 * 1024 // 2MB一片 const chunks = [] let offset = 0 while (offset < file.size) { chunks.push(file.slice(offset, offset + chunkSize)) offset += chunkSize } self.postMessage(chunks) }主线程接收chunks后再逐个调用上传接口,并记录上传进度。这个方案比一次性读完文件,内存占用低了几个量级。
至于“vue项目怎么打包成exe”,两种主流的方案是Electron和Tauri。Electron体积大但生态成熟,Tauri体积小但需要Rust环境。如果你的Vue项目只是内部工具,用Electron打包,把打包后的dist目录塞进一个窗口,就是一个原生应用了。这部分做起来不难,但唯一需要耐心的是第一次运行时下载依赖,慢得让人想摔键盘。
4.3 前后端分离面试高频题复盘
结合热词里的“前端面试题”,我发现面试官特别喜欢问这几个点,而且都跟这个项目里的实践紧密相关:
- Vue响应式原理:Vue3的响应式是基于
Proxy实现的,它比Vue2的Object.defineProperty强在可以拦截属性的新增和删除,深层对象也不需要$set了。 - v-for和v-if为什么不建议一起用:因为
v-for的优先级高于v-if,每次渲染都先循环再判断,白白浪费性能。建议用computed先过滤再渲染。 - 路由懒加载的好处:按需加载页面代码,减小首屏体积,尤其对后台管理系统这种页面很多的场景收益明显。
- Vue3和Vue2的双向绑定区别:Vue2用
v-model和.sync修饰符,Vue3统一为v-model:propsName,支持多个绑定。
面试最后,通常还会让你讲讲“前端八股文”,其实考察的就是你写的代码规不规范、底层原理懂不懂。我的建议是:与其背面试题,不如把上面这个小项目亲手做一遍,面试时直接讲踩坑经历,比背一百道题都管用。
4.4 调试工具使用与前端开发的必备skills
最后补充一个看似基础但很多人真不会的点:Vue调试工具的用法。装了Vue.js devtools扩展后,在页面里能看到每个组件的props、data、computed的实时值。很多人只知道看Network和Console,完全不知道用组件树来定位状态。
我的习惯是:先看Network确认接口请求有没有问题,再看Console看有没有报错,最后打开Vue Devtools逐个组件检查数据流。一个组件的状态不对,顺着组件树往下点,很快就能锁定是父组件传参问题还是子组件内部逻辑问题。
在编码阶段,也要讲究一点“skills”——比如写组件时给props写好类型和默认值、给v-model绑定值做好命名规范、给接口请求做好统一封装。这些看起来是小事,但当你需要维护三个月前的代码时,你会感谢当初的自己。
5. 结语与我的个人体会
这个“VUE前端小例子”做下来,最大的收获不是代码跑通了,而是建立了一套自己的排查思路。很多人在遇到问题时,第一反应是去百度或者问GPT,然后复制粘贴答案。但我建议你先看一眼控制台报错,再拆解一下报错信息里的关键词,最后定位到具体文件。这个过程比答案本身重要得多。
尤其是前端开发,工具链乱、版本杂、浏览器兼容性问题多,debugging的能力才是真正的护城河。在自己的电脑上装好nvm、装好浏览器自动化调试工具,把项目从npm create开始到npm run build结束,每一步都亲手敲一遍,比看一百篇教程都有用。
最后再分享一个小技巧:在写Vue代码时,如果你发现自己反复复制粘贴同一个逻辑,那就该把它抽成composable(自定义组合函数)了。一个成熟的开发者的标志,就是知道自己该在什么时候写重复的代码,什么时候该做抽象。希望这个项目笔记对你有帮助,也欢迎你在实操中遇到问题后回头来对照,看看是不是踩了同样的坑。
本文还有配套的精品资源,点击获取