Vue3 理解为:用组件化方式,把页面、数据、交互和工程结构组织起来的一套前端开发框架。
一、先建立整体框架:Vue3 到底解决什么问题?
传统前端写法通常是:
html
<button id="btn">+1</button>
<span id="count">0</span>
<script>
let count = 0
document.querySelector('#btn').onclick = function () {
count++
document.querySelector('#count').innerText = count
}
</script>
这种写法的问题是:
你要自己找 DOM、改 DOM、维护数据和页面同步。页面小还好,页面一复杂,代码就乱。
Vue3 的核心思想是:
开发者主要维护"数据状态",Vue 自动根据数据变化更新页面。
也就是:
vue
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<button @click="count++">+1</button>
<span>{{ count }}</span>
</template>
你不再手动操作 DOM,而是让 Vue 帮你完成"数据 → 页面"的更新。
二、Vue3 必学核心概念总览
Vue3 的核心基础概念可以按层次理解:
text
Vue3 应用
│
├── 1. createApp:创建应用入口
│
├── 2. 单文件组件 .vue:页面开发的基本单位
│ ├── template:页面结构
│ ├── script setup:逻辑代码
│ └── style:样式
│
├── 3. 响应式数据
│ ├── ref
│ ├── reactive
│ ├── computed
│ └── watch / watchEffect
│
├── 4. 模板语法
│ ├── 插值表达式 {{ }}
│ ├── v-bind
│ ├── v-on
│ ├── v-if
│ ├── v-for
│ └── v-model
│
├── 5. 组件化开发
│ ├── props:父传子
│ ├── emit:子传父
│ ├── slot:插槽
│ └── provide / inject:跨层传递
│
├── 6. 生命周期
│ ├── onMounted
│ ├── onUpdated
│ └── onUnmounted
│
├── 7. 组合式 API
│ ├── setup
│ ├── composable
│ └── 逻辑复用
│
├── 8. 路由 Vue Router
│ ├── 页面切换
│ ├── 动态路由
│ └── 编程式跳转
│
├── 9. 状态管理 Pinia
│ ├── state
│ ├── getters
│ └── actions
│
└── 10. 工程化
├── Vite
├── npm
├── 目录结构
└── 构建部署
Vue 官方文档把组件描述为可以把 UI 拆成独立、可复用的小块;Composition API 则通过 ref()、reactive() 等函数直接创建响应式状态、计算状态和监听器;Pinia 是 Vue 生态中用于共享跨组件状态的状态管理库。(vuejs.org)
三、核心概念逐个讲解
1. createApp:Vue 应用入口
专业解释
createApp() 是 Vue3 创建应用实例的入口函数。它负责创建 Vue 应用,并通过 .mount() 挂载到真实 DOM 容器中。
小白解释
你可以把它理解为:
Vue 项目的"启动按钮"。
HTML 页面里有一个空盒子:
html
<div id="app"></div>
Vue 会把你的应用安装到这个盒子里。
简单案例
js
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
用途
它决定:
这个 Vue 应用从哪个组件开始运行;
挂载到页面中的哪个 DOM 节点;
后续是否安装路由、Pinia、插件等。
2. 单文件组件 SFC:.vue 文件
专业解释
Vue 的单文件组件,也叫 SFC,通常由三部分组成:
vue
<template>
页面结构
</template>
<script setup>
逻辑代码
</script>
<style scoped>
样式代码
</style>
小白解释
一个 .vue 文件就像一个"页面积木块":
template 写页面长什么样;
script 写页面怎么动;
style 写页面好不好看。
简单案例
vue
<template>
<h1>{{ title }}</h1>
</template>
<script setup>
const title = '欢迎学习 Vue3'
</script>
<style scoped>
h1 {
color: blue;
}
</style>
用途
单文件组件让一个功能模块的结构、逻辑、样式集中在一起,便于维护。
例如:
text
StudentCard.vue 学生卡片组件
CourseList.vue 课程列表组件
LoginForm.vue 登录表单组件
3. 响应式数据:ref 和 reactive
这是 Vue3 最核心的概念。
专业解释
Vue3 的响应式系统可以追踪数据变化,并在数据变化后自动触发页面更新。ref() 常用于基本类型,也可以包裹对象;reactive() 常用于对象。Vue 官方文档说明,ref 会让其值具备深层响应式能力,对嵌套对象或数组的修改也能被检测到。(vuejs.org)
小白解释
你可以把响应式数据理解为:
数据和页面之间绑了一根自动同步的线。
数据一变,页面自动变。
ref 案例
vue
<script setup>
import { ref } from 'vue'
const count = ref(0)
function add() {
count.value++
}
</script>
<template>
<button @click="add">点击</button>
<p>当前数量:{{ count }}</p>
</template>
注意:
在 JS 里访问 ref 要写:
js
count.value
在模板里可以直接写:
html
{{ count }}
reactive 案例
vue
<script setup>
import { reactive } from 'vue'
const student = reactive({
name: '张三',
age: 20
})
function grow() {
student.age++
}
</script>
<template>
<p>{{ student.name }} - {{ student.age }}岁</p>
<button @click="grow">年龄+1</button>
</template>
用途
ref 和 reactive 用来保存页面状态,比如:
输入框内容;
按钮点击次数;
用户信息;
列表数据;
接口返回结果。
4. 模板语法:让数据和页面绑定起来
Vue 的模板语法是连接"数据"和"页面"的桥梁。
4.1 插值表达式 {``{ }}
专业解释
插值表达式用于在模板中渲染响应式数据。
小白解释
就是把 JS 里的变量显示到页面上。
案例
vue
<script setup>
const name = '李雷'
</script>
<template>
<p>你好,{{ name }}</p>
</template>
4.2 v-bind:绑定属性
专业解释
v-bind 用于动态绑定 HTML 属性。
简写形式是 :。
小白解释
如果图片地址、按钮状态、链接地址是变量,就用 v-bind。
案例
vue
<script setup>
const imgUrl = 'https://example.com/logo.png'
</script>
<template>
<img :src="imgUrl" />
</template>
等价于:
html
<img v-bind:src="imgUrl" />
4.3 v-on:绑定事件
专业解释
v-on 用于监听 DOM 事件。
简写形式是 @。
小白解释
点击按钮、输入内容、鼠标移动,这些用户动作都可以用它处理。
案例
vue
<script setup>
function sayHello() {
alert('你好')
}
</script>
<template>
<button @click="sayHello">点击</button>
</template>
4.4 v-if:条件渲染
专业解释
v-if 用于根据条件决定元素是否渲染到 DOM 中。
小白解释
满足条件才显示,不满足就不显示。
案例
vue
<script setup>
import { ref } from 'vue'
const isLogin = ref(false)
</script>
<template>
<p v-if="isLogin">欢迎回来</p>
<p v-else>请先登录</p>
</template>
4.5 v-for:列表渲染
专业解释
v-for 用于根据数组或对象循环渲染多个节点。
小白解释
有多少条数据,就自动生成多少个页面元素。
案例
vue
<script setup>
const students = ['张三', '李四', '王五']
</script>
<template>
<ul>
<li v-for="name in students" :key="name">
{{ name }}
</li>
</ul>
</template>
重点
v-for 一般要配合 :key 使用,帮助 Vue 更高效地更新列表。
4.6 v-model:双向绑定
专业解释
v-model 用于表单输入和响应式数据之间建立双向绑定。
小白解释
输入框里打字,变量自动变;变量变,输入框也自动变。
案例
vue
<script setup>
import { ref } from 'vue'
const username = ref('')
</script>
<template>
<input v-model="username" placeholder="请输入用户名" />
<p>你输入的是:{{ username }}</p>
</template>
四、computed:计算属性
专业解释
computed 用于基于已有响应式数据派生出新的数据,并且具有缓存能力。只有依赖的数据发生变化时,计算属性才会重新计算。
小白解释
它像 Excel 里的公式。
比如:
text
总价 = 单价 × 数量
只要单价或数量变了,总价自动变。
案例
vue
<script setup>
import { ref, computed } from 'vue'
const price = ref(10)
const count = ref(2)
const total = computed(() => price.value * count.value)
</script>
<template>
<p>单价:{{ price }}</p>
<p>数量:{{ count }}</p>
<p>总价:{{ total }}</p>
</template>
用途
适合处理:
总价;
筛选后的列表;
格式化后的用户名;
是否可以提交表单;
根据状态派生出来的新状态。
五、watch:监听数据变化
专业解释
watch 用于监听响应式数据的变化,并在变化时执行副作用逻辑,比如请求接口、保存本地缓存、打印日志等。
小白解释
watch 就像一个"观察员"。
它盯着某个数据,一旦数据变了,就立刻做某件事。
案例
vue
<script setup>
import { ref, watch } from 'vue'
const keyword = ref('')
watch(keyword, (newValue, oldValue) => {
console.log('搜索关键词变化了:', newValue)
})
</script>
<template>
<input v-model="keyword" placeholder="请输入搜索关键词" />
</template>
computed 和 watch 的区别
| 概念 | 作用 | 是否返回新值 | 典型用途 |
|---|---|---|---|
| computed | 根据已有数据算出新数据 | 是 | 总价、过滤列表、格式化显示 |
| watch | 监听数据变化后执行动作 | 否 | 发请求、存缓存、打印日志 |
一句话理解:
computed 用来"算结果",watch 用来"做事情"。
六、组件化开发:Vue 的核心开发方式
专业解释
组件是 Vue 应用的基本组织单位。Vue 官方文档指出,组件可以把 UI 拆成独立、可复用的部分,并且可以单独思考每个部分。(vuejs.org)
小白解释
组件就像乐高积木。
一个页面不是一整坨代码,而是由很多小组件拼起来的。
例如一个后台管理页面:
text
App.vue
├── Header.vue
├── Sidebar.vue
├── UserTable.vue
├── SearchForm.vue
└── Pagination.vue
简单案例
父组件 App.vue
vue
<script setup>
import StudentCard from './components/StudentCard.vue'
</script>
<template>
<StudentCard />
</template>
子组件 StudentCard.vue
vue
<template>
<div>
<h3>学生姓名:张三</h3>
<p>专业:计算机科学</p>
</div>
</template>
用途
组件化可以带来:
代码复用;
结构清晰;
多人协作方便;
维护成本低;
页面复杂时不容易混乱。
七、props:父组件给子组件传数据
专业解释
props 是父组件向子组件传递数据的机制。
小白解释
父组件就像家长,子组件像孩子。
家长把数据交给孩子展示。
案例
父组件
vue
<script setup>
import StudentCard from './StudentCard.vue'
</script>
<template>
<StudentCard name="张三" major="软件工程" />
</template>
子组件
vue
<script setup>
defineProps({
name: String,
major: String
})
</script>
<template>
<div>
<h3>{{ name }}</h3>
<p>{{ major }}</p>
</div>
</template>
用途
适合:
父组件把用户信息传给用户卡片;
父组件把商品信息传给商品组件;
父组件把配置项传给按钮、弹窗、表格组件。
八、emit:子组件通知父组件
专业解释
emit 是子组件向父组件发送事件的机制。
小白解释
孩子不能直接改家长的数据,但可以告诉家长:
"我被点击了,你来处理吧。"
案例
子组件 DeleteButton.vue
vue
<script setup>
const emit = defineEmits(['delete'])
function handleClick() {
emit('delete')
}
</script>
<template>
<button @click="handleClick">删除</button>
</template>
父组件
vue
<script setup>
import DeleteButton from './DeleteButton.vue'
function removeItem() {
console.log('父组件执行删除')
}
</script>
<template>
<DeleteButton @delete="removeItem" />
</template>
用途
适合:
子组件按钮点击后通知父组件;
弹窗组件通知父组件关闭;
表单组件通知父组件提交;
列表项通知父组件删除某条数据。
九、slot:插槽
专业解释
slot 用于让父组件向子组件传入一段模板内容。
小白解释
插槽就像一个"预留空位"。
子组件先留一个位置,父组件想放什么就放什么。
案例
Card.vue
vue
<template>
<div class="card">
<slot></slot>
</div>
</template>
父组件
vue
<Card>
<h3>标题</h3>
<p>这是卡片内容</p>
</Card>
用途
适合封装通用组件:
卡片;
弹窗;
布局容器;
按钮;
表格列内容。
十、生命周期:组件从出生到销毁
专业解释
生命周期是组件在创建、挂载、更新、卸载等阶段提供的钩子函数。Vue3 Composition API 中常用的生命周期函数包括 onMounted、onUpdated、onUnmounted 等。官方文档说明,onMounted 通常用于执行需要访问已渲染 DOM 的副作用逻辑。(vuejs.org)
小白解释
一个组件也有"生命过程":
text
创建 → 显示到页面 → 数据变化重新渲染 → 从页面移除
你可以在不同阶段做不同事情。
案例
vue
<script setup>
import { onMounted } from 'vue'
onMounted(() => {
console.log('组件已经显示到页面上了')
})
</script>
<template>
<p>生命周期示例</p>
</template>
用途
常用于:
页面加载后请求接口;
组件显示后获取 DOM;
页面离开前清理定时器;
图表组件初始化;
地图组件初始化。
十一、Composition API:组合式 API
专业解释
Composition API 是 Vue3 推荐的重要写法。它允许开发者使用导入函数来组织组件逻辑,而不是把代码分散在 data、methods、computed 等选项中。官方文档说明,Composition API 包含响应式 API,例如 ref()、reactive(),可以直接创建响应式状态、计算状态和监听器。(vuejs.org)
小白解释
传统写法像这样:
text
数据放一个地方
方法放一个地方
计算属性放一个地方
监听器放一个地方
功能一复杂,同一个业务逻辑会被拆得很散。
Composition API 的好处是:
和"用户搜索"相关的代码放一起,和"购物车"相关的代码放一起,和"登录"相关的代码放一起。
案例
vue
<script setup>
import { ref, computed } from 'vue'
const keyword = ref('')
const list = ref(['Vue', 'React', 'Angular'])
const filteredList = computed(() => {
return list.value.filter(item => item.includes(keyword.value))
})
</script>
<template>
<input v-model="keyword" />
<ul>
<li v-for="item in filteredList" :key="item">
{{ item }}
</li>
</ul>
</template>
用途
Composition API 特别适合:
复杂页面;
逻辑复用;
大型项目;
TypeScript 项目;
把业务逻辑抽离成 composable。
十二、Composable:可复用逻辑函数
专业解释
Composable 是基于 Composition API 抽离出来的可复用逻辑函数,通常命名为 useXxx。
小白解释
如果多个页面都要用同一套逻辑,就不要复制粘贴,而是把它封装成一个函数。
案例:封装计数逻辑
useCounter.js
js
import { ref } from 'vue'
export function useCounter() {
const count = ref(0)
function add() {
count.value++
}
function minus() {
count.value--
}
return {
count,
add,
minus
}
}
组件中使用
vue
<script setup>
import { useCounter } from './useCounter'
const { count, add, minus } = useCounter()
</script>
<template>
<button @click="minus">-</button>
<span>{{ count }}</span>
<button @click="add">+</button>
</template>
用途
适合复用:
搜索逻辑;
分页逻辑;
表单校验逻辑;
接口请求逻辑;
倒计时逻辑;
弹窗开关逻辑。
十三、Vue Router:前端路由
专业解释
Vue Router 是 Vue 的官方路由工具,用于管理单页应用中的页面切换。Vue Router 4 可用于 Vue3,并支持 Composition API 和 Options API;官方文档也说明,Vue3 应使用 Vue Router 4,而 Vue Router 3 是面向 Vue2 的旧版本。(router.vuejs.org)
小白解释
传统网站跳页面是:
text
浏览器重新请求一个新 HTML 页面
Vue 单页应用中,页面切换通常是:
text
不刷新整个页面,只切换中间显示的组件
案例
路由配置
js
import { createRouter, createWebHistory } from 'vue-router'
import Home from './views/Home.vue'
import About from './views/About.vue'
const router = createRouter({
history: createWebHistory(),
routes: [
{ path: '/', component: Home },
{ path: '/about', component: About }
]
})
export default router
main.js
js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
createApp(App).use(router).mount('#app')
App.vue
vue
<template>
<router-link to="/">首页</router-link>
<router-link to="/about">关于</router-link>
<router-view />
</template>
用途
Vue Router 用来实现:
首页;
详情页;
登录页;
后台管理页面;
菜单导航;
动态路由;
权限路由。
十四、Pinia:状态管理
专业解释
Pinia 是 Vue 官方生态推荐的状态管理库,用于管理跨组件、跨页面共享的数据。Pinia 官方文档说明,Store 是保存状态和业务逻辑的实体,不绑定到组件树;它包含 state、getters、actions,这三者可以类比为组件中的 data、computed、methods。(pinia.vuejs.org)
Vue 官方文档也提到,Pinia 由 Vue 核心团队维护,Vuex 目前处于维护模式,新项目推荐使用 Pinia。(vuejs.org)
小白解释
如果只是父子组件传数据,用 props 和 emit 就够了。
但如果很多页面都要用同一份数据,比如:
当前登录用户;
购物车;
系统主题;
权限菜单;
全局消息;
这时候就需要 Pinia。
它像一个"全局仓库"。
案例
stores/user.js
js
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', {
state: () => ({
name: '张三',
isLogin: false
}),
getters: {
welcomeText: state => `欢迎,${state.name}`
},
actions: {
login(name) {
this.name = name
this.isLogin = true
}
}
})
组件中使用
vue
<script setup>
import { useUserStore } from './stores/user'
const userStore = useUserStore()
function handleLogin() {
userStore.login('李四')
}
</script>
<template>
<p>{{ userStore.welcomeText }}</p>
<button @click="handleLogin">登录</button>
</template>
用途
Pinia 适合管理:
用户信息;
购物车数据;
后台权限;
跨页面共享状态;
主题设置;
多组件共享的业务状态。
十五、接口请求:前端和后端交互
专业解释
Vue 本身不限定请求库,项目中常用 fetch 或 axios 与后端 API 通信。接口返回的数据通常保存到 ref 或 reactive 中,再由模板渲染。
小白解释
Vue 页面不是所有数据都写死在前端。
很多数据来自服务器,比如:
学生列表;
商品列表;
新闻列表;
登录结果;
课程信息。
案例
vue
<script setup>
import { ref, onMounted } from 'vue'
const students = ref([])
onMounted(async () => {
const res = await fetch('/api/students')
students.value = await res.json()
})
</script>
<template>
<ul>
<li v-for="stu in students" :key="stu.id">
{{ stu.name }}
</li>
</ul>
</template>
用途
真实项目中,Vue 主要负责:
展示后端数据;
收集用户输入;
调用接口提交数据;
根据接口结果更新页面。
十六、工程化:Vite、npm、目录结构
专业解释
Vue3 项目通常使用 Vite 作为构建工具,通过 npm 管理依赖,并采用模块化目录结构组织代码。
小白解释
写几个 HTML 文件可以不用工程化。
但做真正项目时,需要:
自动启动开发服务器;
自动热更新;
打包压缩代码;
安装第三方库;
管理多个组件和页面。
这就是工程化。
常见目录结构
text
src
├── assets 静态资源
├── components 公共组件
├── views 页面组件
├── router 路由配置
├── stores Pinia 状态管理
├── utils 工具函数
├── api 接口请求
├── App.vue 根组件
└── main.js 应用入口
十七、把所有概念串起来:一个 Todo 小案例
下面这个案例可以把 Vue3 的核心概念串起来。
功能
输入任务;
点击添加;
显示任务列表;
点击删除;
显示任务总数。
vue
<script setup>
import { ref, computed } from 'vue'
const newTodo = ref('')
const todos = ref([
{ id: 1, text: '学习 Vue3 基础' },
{ id: 2, text: '练习组件化开发' }
])
const total = computed(() => todos.value.length)
function addTodo() {
if (!newTodo.value.trim()) return
todos.value.push({
id: Date.now(),
text: newTodo.value
})
newTodo.value = ''
}
function removeTodo(id) {
todos.value = todos.value.filter(todo => todo.id !== id)
}
</script>
<template>
<div>
<h2>任务清单</h2>
<input v-model="newTodo" placeholder="请输入任务" />
<button @click="addTodo">添加</button>
<p>当前任务数量:{{ total }}</p>
<ul>
<li v-for="todo in todos" :key="todo.id">
{{ todo.text }}
<button @click="removeTodo(todo.id)">删除</button>
</li>
</ul>
</div>
</template>
这个例子中:
| 代码 | 用到的 Vue 概念 |
|---|---|
ref('') |
响应式数据 |
computed() |
计算属性 |
v-model |
表单双向绑定 |
@click |
事件绑定 |
v-for |
列表渲染 |
:key |
列表更新优化 |
{``{ total }} |
插值表达式 |
addTodo() |
方法逻辑 |
removeTodo() |
数据驱动页面更新 |
十八、Vue3 核心概念之间的逻辑关系
你可以这样理解 Vue3 的整体运行逻辑:
text
用户操作页面
↓
触发事件 @click / @input
↓
修改响应式数据 ref / reactive
↓
computed 自动重新计算
↓
template 自动重新渲染
↓
页面更新
再往项目层面扩展:
text
main.js
创建 Vue 应用
↓
App.vue
根组件
↓
Vue Router
决定当前显示哪个页面组件
↓
页面组件 views
组织业务页面
↓
公共组件 components
拆分可复用 UI
↓
props / emit / slot
完成组件通信
↓
Pinia
管理跨页面共享状态
↓
API 请求
和后端交换数据
十九、学习 Vue3 的推荐顺序
建议你按这个顺序学:
text
第一阶段:基础语法
1. Vue 项目创建
2. .vue 单文件组件
3. 插值表达式
4. v-bind
5. v-on
6. v-if
7. v-for
8. v-model
第二阶段:响应式核心
9. ref
10. reactive
11. computed
12. watch
13. 生命周期
第三阶段:组件化
14. 组件拆分
15. props
16. emit
17. slot
18. provide / inject
第四阶段:项目开发
19. Vue Router
20. Pinia
21. axios / fetch
22. 表单
23. 权限
24. 项目目录结构
第五阶段:进阶
25. composable
26. TypeScript
27. 性能优化
28. 组件库
29. 打包部署
30. SSR / Nuxt
二十、一句话总结 Vue3
Vue3 的核心不是"多背几个指令",而是理解这条主线:
用组件组织页面,用响应式数据驱动页面,用模板声明页面结构,用事件修改状态,用路由组织页面切换,用 Pinia 管理全局数据,用工程化工具组织大型项目。
掌握这条主线后,你再看任何 Vue3 项目,基本都能知道:
哪个文件是入口;
哪个组件负责页面;
数据在哪里;
事件在哪里;
接口在哪里;
路由在哪里;
全局状态在哪里。