简介:VUE前端小例子是一份面向Vue初学者与前端开发者的入门实践资源,围绕资产管理等小场景演示Vue实例创建、双向数据绑定、计算属性、组件化开发、路由配置及模板语法等核心知识点,适合用于理解Vue工程化项目的基本构成与常见写法。资源包共39个文件,以js逻辑文件、vue组件文件和png图片为主,并包含json配置、webpack构建脚本及说明文档,整体压缩包仅45KB,结构紧凑便于快速查阅。目前已有4211人学习下载,内容整理了完整的Vue项目骨架,涵盖src组件目录、router路由、build配置等典型模块,读者可对照代码掌握Vue指令、计算属性与侦听器、组件拆分与复用等实践技巧,并借此熟悉基于webpack的Vue项目搭建与调试流程。压缩包内目录层级清晰,业务代码与构建脚本分离,配合静态资源与说明文件,适合边阅读边运行验证,为后续独立开发或团队协作打下扎实基础。
1. 为什么把 Vue 前端小例子当成脚手架来拆:从 Hello World 到可运行工程
一套 Vue 前端小例子,看起来是最不起眼的资源,实际拆开才发现它比很多“完整项目”更好用。因为例子是单点验证过的,组件通信、表单双向绑定、路由跳转、列表渲染这些 Vue 前端技,都被拆成了独立可运行的片段,省去了从零搭骨架的时间。我的习惯是拿到这类资源先别急着看代码,先把运行环境跑通,再按目录反推每个例子在验证什么。适合谁?中后台开发转 Vue 前端的新手,或者手头有页面要快速出 Demo 的从业者。复现这套 Vue 例子,你得到的不只是代码,是一套可以反复用的 Vue 实现资。
2. Vue 前端小例子里的技术底座:选项式与组合式 API 怎么选
先花一章把原理讲透,因为后面动手改例子时,你会不停地在这两套写法之间切换。
2.1 选项式 API:data、methods、computed 的分工逻辑
这套 Vue 例子里的早期示例,基本都是选项式写法。data 管数据,methods 管行为,computed 管派生值,watch 管副作用。理解它的关键在于:data 里声明的每个字段都会被 Vue 转成响应式代理,模板里直接访问的就是这个代理对象上的属性。
export default { data() { return { searchText: '', todoList: [ { id: 1, title: '写 Vue 例子拆解', done: false } ] } }, computed: { remainingCount() { return this.todoList.filter(item => !item.done).length } }, methods: { addTodo() { if (!this.searchText.trim()) return this.todoList.push({ id: Date.now(), title: this.searchText.trim(), done: false }) this.searchText = '' } } }这段代码逻辑比较直白:searchText 绑定输入框,addTodo 把输入内容推进 todoList,remainingCount 根据 done 字段动态计算未完成数量。参数上要注意两点。getter 里return this.todoList.filter(...)的 this 指向组件实例,别用箭头函数包一层,否则 this 会丢。还有 computed 的缓存机制,它依赖的 todoList 不变,remainingCount 就不会重算,这比在 methods 里写函数更省性能。
常见误用是把 computed 当 methods 用,在模板里写成remainingCount(),或者反过来把复杂逻辑塞进 methods 然后在多个地方重复调用。例子里的写法是标准的:需要缓存、依赖多个响应式数据时用 computed,需要传参、处理事件时用 methods。
2.2 组合式 API:setup 与 ref/reactive 的取舍
这套资源里偏新的例子用的就是组合式 API。核心区别不用背概念,直接看数据声明的写法差异:选项式把数据挂到 data 函数的 return 里,组合式则把逻辑全部收敛到 setup 函数或<script setup>块中。
import { ref, reactive, computed } from 'vue' const searchText = ref('') const state = reactive({ list: [], loading: false }) const filteredList = computed(() => { return state.list.filter(item => item.title.includes(searchText.value)) }) function loadList() { state.loading = true setTimeout(() => { state.list = [ { id: 1, title: 'Vue 例子第一讲' }, { id: 2, title: 'Vue 例子第二讲' } ] state.loading = false }, 500) } loadList()ref 和 reactive 的取舍是这里的重点:ref 包装基本类型和对象,script 里访问要带 .value,模板里自动解包;reactive 只能包装对象,script 和模板里都不用加 .value。参数上说说为什么经常用 ref:因为它对类型的限制更少,而且在 setup 里返回、传参、解构都不容易丢失响应式。reactive 最大的坑是解构,const { list } = state之后 list 就失去响应式了,要用 toRefs 包一层才能解构。这套例子里凡是用 reactive 的,要么不解构,要么提前做了 toRefs 处理。
组合式 API 适合什么场景?例子比较多的时候,比如多个功能模块要抽公共逻辑,用自定义 hook 的方式复用。同一套代码里,如果有一半交互逻辑要跨组件共享,就别死守选项式。反过来,页面简单、组件不复杂时,选项式反而更直观,找数据去 data,找方法去 methods。
3. 复现这套 Vue 例子的完整操作:环境搭建、运行到改造成自己的代码
这一章是可抄作业的部分,从零开始把这套 Vue 例子跑起来,再手动改一个例子变成你自己的代码。
3.1 搭建运行环境:Vite 脚手架、依赖安装与 npm run dev
拿到这套 Vue 前端小例子的目录后,不要直接用浏览器打开 HTML 文件,Vue 例子多数是单文件组件,需要构建工具跑起来才能看到效果。这里推荐用 Vite,比 Webpack 配置少,启动快,处理单文件组件也稳定。
npm create vite@latest vue-demo -- --template vue cd vue-demo npm install npm run dev三条命令的含义拆开说:第一条用 Vite 的官方模板生成项目骨架,--template vue指定 Vue 版本模板(默认是 Vue 3);npm install是安装 package.json 里声明的所有依赖,这里注意锁文件,项目里如果自带 package-lock.json,推荐用它安装,别随手删;npm run dev启动开发服务器,终端会输出本地访问地址,默认是http://localhost:5173。
跑起来之后怎么做?把你下载的资源里各例子目录下的 .vue 文件或 .js 文件,逐个对照着放进去。这套例子的目录结构一般是 components(组件)、views(页面)、router(路由)、store(状态)。把下载目录里的 src 内容整体替换掉模板项目里的 src,注意保留模板的 main.js 入口文件,除非资源自带入口。
# 查看资源目录结构,确认入口文件位置 find ./vue-examples -maxdepth 2 -type f | sort这条命令的作用是快速看清资源里有哪些文件。看到 main.js 在根目录下的,直接把它复制到模板项目的 src 目录下。看到路由配置文件 router/index.js 的,同样复制过去。R 参数要说明的是,案例资源里不同版本依赖不同,Vue 3 的用 vue-router 4,Vue 2 的用 vue-router 3,复制之前先看 package.json 里的依赖声明,版本对不上要先改 package.json 再 npm install。
3.2 动手改造一个例子:把写死的列表改成接口数据
运行通过之后,选一个列表渲染的例子来改。最常见的场景是:例子里有个写死的数组,你要把它换成后端接口返回的数据。这个改造只要动三个地方:数据声明、生命周期钩子、模板结构。
import { ref, onMounted } from 'vue' const userList = ref([]) const loading = ref(true) async function fetchUserList() { try { const response = await fetch('/api/users') if (!response.ok) throw new Error('接口异常') const result = await response.json() userList.value = result.data } catch (error) { console.error('拉取用户列表失败:', error) } finally { loading.value = false } } onMounted(fetchUserList)这段的关键点是:userList 用 ref 包裹,才能在异步回调里通过.value赋值并触发模板更新;onMounted是组合式 API 的挂载钩子,保证页面渲染完成后才发起请求;finally里关 loading,这样无论是成功还是失败,加载状态都会被复位。
改完之后检查模板部分:
<template> <div> <div v-if="loading">加载中...</div> <ul v-else> <li v-for="item in userList" :key="item.id"> {{ item.name }} - {{ item.role }} </li> </ul> </div> </template>v-if / v-else 是配套出现的,loading 为真时显示加载提示,假时显示列表。v-for 遍历 userList,:key绑定到唯一标识 id,避免 Vue 复用错误 DOM 节点。这里有个细节:接口返回结构可能是{ code, data, message },也可能是{ data: [...] },每个团队风格不一样,接自己后端时先打印一次 response。json() 看清结构再写取值逻辑,我一般会随手console.log(result)一次再继续。
4. 跑 Vue 例子最常见的四类问题排查:环境、版本、热更新与数据流
跑这套 Vue 例子的过程中,我踩过的坑集中在这四类,每条都是现象、原因、解决三步说透。
4.1 安装依赖时卡在 node_modules:镜像源、lock 文件与缓存清理
现象:npm install 执行后长时间停在理想树构建,或者报错提示 ERESOLVE unable to resolve dependency tree。原因:当前 npm 镜像源访问慢,包版本冲突,尤其是依赖里同时出现 Vue 2 和 Vue 3 的生态库时最容易撞。解决:先确认镜像源配置,再检查项目依赖版本,最后考虑清缓存。下面这段是我的标准处理流程:
npm config get registry npm config set registry https://registry.npmmirror.com rm -rf node_modules package-lock.json npm cache clean --force npm install第一条命令是看当前 registry 指向哪里,默认是官方源的,慢或不通就换成国内镜像源。删 lock 文件是无奈之举,但确实能解决一部分版本锁死的问题。npm cache clean 清的是本地 npm 缓存,能排除缓存损坏的干扰。注意,删除 lock 文件属于兜底操作,如果项目是团队协作的,改完之后要确认 lock 变更不会影响别人的构建。
4.2 例子直接复制过来白屏:组件注册、路由配置与大小写
现象:npm run dev 不报错,浏览器打开是空白页,F12 控制台有警告或报错。原因:复制过来时组件文件改名了,但引用处没同步;或者路由配置的 component 导入路径不对;又或者是文件名大小写和导入语句不一致。解决:白屏问题按顺序查三条,第一条查注册,第二条查路由,第三条查大小写。
# 在 src 目录下全局搜索组件引用名与实际文件名 grep -r "import .* from" src --include="*.vue" --include="*.js" | head -30拿到输出后人工核对每个 import 的文件名大小写和路径后缀。Vue 单文件组件里,import UserCard from './components/UserCard.vue'文件实际叫 usercard.vue,在 Linux 环境下会挂,因为文件系统区分大小写;在 Windows 下可能不挂,但换到部署环境就挂。所以我拿到别人给的例子,第一件事是把所有 import 路径和实际文件做一次 diff,遇到不一致的按实际文件名修改。
4.3 热更新不生效或页面不刷新:文件监听、编辑器保存与沙箱
现象:改完 .vue 文件,浏览器页面毫无反应,手动刷新才看到最新代码。原因:开发服务器文件监听失效,可能是文件路径包含中文或特殊字符,也可能是编辑器保存时没有触发文件系统事件。解决:先用命令行确认 dev server 有没有捕获到文件变更,再检查路径。
# 开启 Vite 的 debug 日志确认文件监听状态 npx vite --debug看到输出里有hmr update字样的说明热更新生效,没出现就说明监听失效。常见处理思路:把整个项目挪到纯英文路径下再跑,关闭编辑器里的安全写入功能。某一次我遇到改代码不生效,查了半天发现是编辑器的“自动保存到临时文件再重命名”机制,把文件事件搞丢了,关闭这个选项后重启 dev server 恢复。提醒:热更新不生效时别急着重启服务,先确认事件有没有到达 dev server,连事件都没到,重启一百次也没用。
4.4 组件通信改了一遍还是没反应:props 单向数据流与事件名
现象:父组件传值给子组件,子组件模板上显示的还是初始值,或者子组件 emit 了一个事件,父组件监听不到。原因:第一种子组件内部直接修改了 props,第二种事件名大小写不一致或 emit 名与监听名对不上。解决:props 单向数据流的含义是子组件不允许直接改 props,要改就发事件让父组件自己改。
// 子组件:用本地 data 作为中转,监听 props 变化 export default { props: { visible: { type: Boolean, default: false } }, emits: ['update:visible'], data() { return { innerVisible: this.visible } }, watch: { visible(newVal) { this.innerVisible = newVal } }, methods: { closeDialog() { this.innerVisible = false this.$emit('update:visible', false) } } }这块代码的关键在于两点:watch监听 props 变化并同步到本地 data,配合distinct,$emit只负责通知父组件,不直接改 visible。事件名update:visible是 Vue 3 里配合 v-model 的约定写法,父组件用v-model:visible="showDialog"即可实现双向绑定。踩坑记录:事件名写成 camelCase,监听时用了 kebab-case,对不上导致事件丢失。Vue 3 官方模板中事件名推荐用 kebab-case 字符串形式,避免这种问题的出现。
5. 从一个例子到一个小项目:组合各组件的进阶改造
把几个零散例子串成一个完整的小应用,是这套资源最有价值的用法。先说思路:把列表例子当数据展示层,把表单例子当数据输入层,把详情例子当数据消费层,三层之间用路由串联,用 props 传参,用事件或状态管理做横向通信。
具体实操中,我会先建一个主布局组件,把侧边导航和内容区域空出来,再把列表页、表单页、详情页分别放入内容区域。路由配置用动态 import 做按需加载,数据状态则统一提升到父组件或一个简单的 store 里。验证标准是:在列表页点新增,跳转表单页提交,返回列表页能看到新数据,这一条链路走通就说明各组件之间没脱节。
import { createRouter, createWebHashHistory } from 'vue-router' import MainLayout from '../layouts/MainLayout.vue' const routes = [ { path: '/', component: MainLayout, children: [ { path: '', name: 'list', component: () => import('../views/ListView.vue') }, { path: 'form', name: 'form', component: () => import('../views/FormView.vue') }, { path: 'detail/:id', name: 'detail', component: () => import('../views/DetailView.vue') } ] } ]嵌套路由的好处是:MainLayout 的公共部分只渲染一次,子路由切换只替换子组件区域。参数说明:createWebHashHistory用哈希路由,部署到静态服务器不用额外配置,写后台管理系统够用;() => import()是动态导入,路由切换时才加载对应组件,缩小首屏体积。
这套改造做完之后我发现一个习惯特别有用:每集成一个新例子,先跑通原版,再复制一份改名做改造,改完用第 4 章的排查清单过一遍,确认环境和版本没问题再删掉原版备份。因为这套例子里有些版本混用了 Vue 2 和 Vue 3 的写法,直接改原版容易越改越乱,留一份原始资源做用于对照,相当于给自己留了一颗后悔药。从那以后,我每次拿到新的 Vue 例子资源,都强制自己走一遍“跑通 → 对照 → 改造 → 验证”的流程,这个流程帮我省下的排查时间远远超过了初次跑通的时间。希望帮到你。
本文还有配套的精品资源,点击获取