前言
本教程基于Vue3 + Vite(目前企业主流技术栈),覆盖 Vue3 全部核心功能、进阶特性、工程化用法,全程搭配可直接复制运行的实战案例,无跳过、无省略、无废话,零基础可学,资深开发者可查漏补缺。
教程特点:功能大纲系统化 + 知识点精讲 + 代码实战 + 场景说明 + 避坑指南,真正做到学完即用。
运行环境:Node.js 16+、VSCode、Vue3 单文件组件(SFC)
一、Vue3 完整功能大纲(系统化目录)
1. 基础核心
-
Vue 简介、搭建项目、模板语法
-
插值、指令、修饰符
-
响应式基础(ref/reactive)
-
计算属性、侦听器
-
样式绑定、Class绑定
-
条件渲染、列表渲染
-
事件处理、表单双向绑定
2. 组件基础
-
组件注册、父子组件通信
-
Props 校验、默认值
-
组件事件 emit
-
插槽(默认插槽、具名插槽、作用域插槽)
-
组件生命周期
3. 组合式API(Vue3核心)
-
setup 语法糖、执行时机
-
ref / reactive / toRefs / toRef
-
computed 计算属性
-
watch / watchEffect 侦听
-
生命周期组合式API(onMounted/onUpdated等)
-
provide / inject 跨层通信
-
mitt 全局事件总线
-
自定义hooks封装
4. 高阶进阶特性
-
响应式原理精讲
-
Teleport 瞬移组件
-
Suspense 异步加载组件
-
KeepAlive 组件缓存
-
动态组件、异步组件
-
自定义指令
-
nextTick 异步更新队列
5. Vue工程化配套
-
Vue Router 路由(基础+高阶)
-
Pinia 状态管理
-
Vite 工程配置、环境变量
-
组件封装、项目规范
二、环境搭建(保姆级第一步)
1. 创建Vue3项目(Vite)
打开终端,依次执行命令:
# 创建项目
npm create vite@latest vue3-demo -- --template vue
# 进入项目
cd vue3-demo
# 安装依赖
npm install
# 启动项目
npm run dev
启动成功后,访问http://localhost:5173 即可运行所有案例。后续所有代码均替换 src/App.vue 直接运行。
三、Vue3 基础核心(带实战案例)
1. 模板语法与插值
核心作用:在HTML中嵌入Vue变量、表达式,实现数据动态渲染。
规则:插值仅支持单行简单表达式,不支持语句、复杂逻辑。
实战案例:基础插值渲染
<template>
<div class="demo">
<!-- 基础变量插值 -->
<p>用户名:{{ username }}</p>
<!-- 表达式运算 -->
<p>年龄+5:{{ age + 5 }}</p>
<!-- 三元表达式 -->
<p>状态:{{ isVip ? '会员' : '普通用户' }}</p>
<!-- 方法调用 -->
<p>拼接内容:{{ getText() }}</p>
</div>
</template>
<script setup>
// 定义响应式变量
const username = "Vue工程师";
const age = 25;
const isVip = true;
// 定义方法
const getText = () => {
return "顶级" + username;
};
</script>
2. 核心指令大全(常用全覆盖)
2.1 v-text / v-html
v-text:纯文本渲染,覆盖标签内容;v-html:解析HTML标签渲染(注意防XSS攻击)。
<template>
<p v-text="text"></p>
<p v-html="htmlStr"></p>
</template>
<script setup>
const text = "纯文本内容";
const htmlStr = "<span style='color:red'>红色HTML文本</span>";
</script>
2.2 v-bind 属性绑定(简写 :)
动态绑定HTML属性(class、style、src、title等),是最常用指令之一。
<template>
<!-- 完整写法 -->
<img v-bind:src="imgUrl" alt="">
<!-- 简写写法(企业主流) -->
<a :href="link">跳转链接</a>
<div :title="tip">鼠标悬浮提示</div>
</template>
<script setup>
const imgUrl = "https://picsum.photos/200/200";
const link = "https://cn.vuejs.org/";
const tip = "Vue3官方文档";
</script>
2.3 v-on 事件绑定(简写 @)
绑定点击、输入、键盘等事件,支持传参、事件对象、修饰符。
<template>
<!-- 无参事件 -->
<button @click="handleClick">点击按钮</button>
<!-- 传参事件 -->
<button @click="handleParams(100, 'Vue')">传参点击</button>
<!-- 获取事件对象 -->
<button @click="handleEvent($event)">获取事件对象</button>
<!-- 常用修饰符:prevent阻止默认行为 -->
<a @click.prevent="handleLink" href="https://www.baidu.com">阻止跳转</a>
</template>
<script setup>
// 无参方法
const handleClick = () => {
alert("按钮被点击了");
};
// 带参方法
const handleParams = (num, str) => {
alert(`参数:${num}、${str}`);
};
// 获取事件对象
const handleEvent = (e) => {
console.log("事件对象:", e.target);
};
// 阻止默认行为
const handleLink = () => {
alert("已阻止链接跳转");
};
</script>
2.4 v-model 双向绑定
表单核心指令,实现数据驱动视图、视图更新数据双向同步,支持所有表单元素。
<template>
<!-- 输入框双向绑定 -->
<input v-model="inputValue" placeholder="请输入内容">
<p>实时输入内容:{{ inputValue }}</p>
<!-- 单选框 -->
<input type="radio" v-model="gender" value="男">男
<input type="radio" v-model="gender" value="女">女
<p>选中性别:{{ gender }}</p>
<!-- 复选框 -->
<input type="checkbox" v-model="hobby" value="编程">编程
<input type="checkbox" v-model="hobby" value="阅读">阅读
<p>选中爱好:{{ hobby }}</p>
</template>
<script setup>
// 双向绑定变量
const inputValue = "";
const gender = "男";
const hobby = [];
</script>
2.5 条件渲染 v-if / v-show
v-if:惰性渲染,条件为false时销毁DOM,适合切换频率低场景; v-show:通过CSS隐藏显示,DOM始终存在,适合频繁切换场景。
<template>
<div>
<h3>v-if 条件渲染</h3>
<p v-if="score >= 90">优秀</p>
<p v-else-if="score >= 60">及格</p>
<p v-else>不及格</p>
<h3>v-show 切换显示</h3>
<p v-show="isShow">我是可切换显示的内容</p>
<button @click="isShow = !isShow">切换显示隐藏</button>
</div>
</template>
<script setup>
const score = 85;
let isShow = true;
</script>
2.6 列表渲染 v-for
遍历数组、对象,渲染列表,key必须唯一(推荐用id,不推荐用index)。
<template>
<div>
<h3>数组列表渲染</h3>
<ul>
<li v-for="(item, index) in list" :key="item.id">
{{ index + 1 }} - {{ item.name }} - {{ item.age }}岁
</li>
</ul>
<h3>对象遍历渲染</h3>
<ul>
<li v-for="(value, key) in userInfo" :key="key">
{{ key }}:{{ value }}
</li>
</ul>
</div>
</template>
<script setup>
// 数组数据
const list = [
{ id: 1, name: "张三", age: 20 },
{ id: 2, name: "李四", age: 22 },
{ id: 3, name: "王五", age: 24 }
];
// 对象数据
const userInfo = {
姓名: "Vue工程师",
岗位: "前端开发",
工龄: "3年"
};
</script>
3. Vue3 响应式核心(ref / reactive)
Vue3响应式是核心特性,实现数据变、视图自动更新,两种API分工明确。
-
ref:适配基本数据类型(字符串、数字、布尔),也可适配对象,取值需要 .value
-
reactive:仅适配引用数据类型(对象、数组),无需 .value
实战案例:响应式数据更新
<template>
<div>
<p>ref数值:{{ num }}</p>
<p>reactive用户姓名:{{ user.name }}</p>
<button @click="updateData">更新响应式数据</button>
</div>
</template>
<script setup>
// ref 定义基本类型响应式
import { ref, reactive } from 'vue';
const num = ref(10);
// reactive 定义对象响应式
const user = reactive({
name: "小明",
age: 20
});
// 修改数据方法
const updateData = () => {
// ref修改必须加 .value
num.value = 99;
// reactive直接修改属性
user.name = "Vue顶级工程师";
};
</script>
避坑指南:script-setup中,模板使用ref变量无需写.value,仅JS逻辑中需要。
4. 计算属性 computed
核心作用:基于现有数据派生新数据,自带缓存,依赖不变则不重复计算,适合复杂逻辑计算。
实战案例:购物车价格计算
<template>
<div>
<p>单价:{{ price }}元</p>
<p>数量:{{ count }}件</p>
<p>总价(计算属性):{{ totalPrice }}元</p>
<button @click="count++">数量+1</button>
</div>
</template>
<script setup>
import { ref, computed } from 'vue';
const price = ref(99);
const count = ref(1);
// 只读计算属性
const totalPrice = computed(() => {
console.log("计算执行了");
return price.value * count.value;
});
</script>
核心优势:多次渲染页面,只要price、count不变,控制台只会打印一次,性能远优于直接写表达式。
5. 侦听器 watch / watchEffect
用于监听数据变化,执行异步操作、复杂逻辑(接口请求、数据持久化等)。
5.1 watch 精准监听
<template>
<input v-model="keyword" placeholder="输入关键词监听变化">
</template>
<script setup>
import { ref, watch } from 'vue';
const keyword = ref("");
// 监听单个数据
watch(keyword, (newVal, oldVal) => {
console.log("新值:", newVal, "旧值:", oldVal);
// 可在这里做搜索防抖、接口请求
}, { immediate: true }); // immediate: 初始加载立即执行
</script>
5.2 watchEffect 自动依赖收集
无需指定监听对象,自动收集内部依赖,依赖变化自动执行,代码更简洁。
<script setup>
import { ref, watchEffect } from 'vue';
const id = ref(1);
watchEffect(() => {
// 自动监听id变化
console.log("当前ID:", id.value);
// 模拟接口请求
// axios.get(`/api/list?id=${id.value}`)
});
</script>
四、组件核心实战(企业高频用法)
1. 父子组件通信 Props + Emit
组件通信是Vue开发核心,父传子用Props,子传父用emit自定义事件。
步骤1:创建子组件 src/components/Child.vue
<template>
<div class="child">
<p>子组件接收父组件数据:{{ msg }}</p>
<button @click="sendMsg">子组件向父组件传值</button>
</div>
</template>
<script setup>
// 1. 接收父组件参数 + 类型校验 + 默认值
const props = defineProps({
msg: {
type: String,
default: "默认消息",
required: true
}
});
// 2. 定义自定义事件
const emit = defineEmits(['child-event']);
// 子组件触发事件
const sendMsg = () => {
emit("child-event", "我是子组件传递的内容");
};
</script>
步骤2:父组件 App.vue 使用
<template>
<div class="parent">
<h3>父组件</h3>
<Child :msg="parentMsg" @child-event="getChildData" />
<p>接收子组件数据:{{ childData }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue';
import Child from './components/Child.vue';
// 父组件数据
const parentMsg = ref("父组件专属消息");
const childData = ref("");
// 接收子组件传值
const getChildData = (val) => {
childData.value = val;
};
</script>
2. 插槽全解析(默认/具名/作用域插槽)
插槽实现组件内容自定义,是封装通用组件的核心。
2.1 默认插槽
子组件预留位置,父组件传入任意内容。
<!-- 子组件 SlotDemo.vue -->
<template>
<div class="box">
<p>组件固定头部</p>
<slot>默认占位内容</slot>
<p>组件固定底部</p>
</div>
</template>
<!-- 父组件使用 -->
<SlotDemo>
<p>父组件自定义插入的内容</p>
</SlotDemo>
2.2 具名插槽
多个插槽精准匹配,实现多区域自定义。
<!-- 子组件 -->
<template>
<slot name="header"></slot>
<slot></slot>
<slot name="footer"></slot>
</template>
<!-- 父组件使用 -->
<SlotDemo>
<template #header>
<h3>自定义头部</h3>
</template>
<p>默认主体内容</p>
<template #footer>
<p>自定义底部</p>
</template>
</SlotDemo>
2.3 作用域插槽(高级)
子组件数据传给父组件,父组件自定义渲染格式,表格、列表封装必备。
<!-- 子组件 -->
<template>
<ul>
<li v-for="item in list" :key="item.id">
<slot :row="item">{{ item.name }}</slot>
</li>
</ul>
</template>
<script setup>
const list = [
{ id: 1, name: "Vue", desc: "前端框架" },
{ id: 2, name: "Vite", desc: "构建工具" }
];
</script>
<!-- 父组件使用 -->
<ScopeSlot>
<template #default="scope">
<strong>{{ scope.row.name }}:{{ scope.row.desc }}</strong>
</template>
</ScopeSlot>
3. 组件生命周期(组合式API)
生命周期是组件从创建、挂载、更新、销毁的全过程,用于处理组件不同阶段逻辑。
实战案例:生命周期执行顺序
<script setup>
import {
onBeforeMount, onMounted,
onBeforeUpdate, onUpdated,
onBeforeUnmount, onUnmounted
} from 'vue';
// 挂载前
onBeforeMount(() => console.log("挂载前"));
// 挂载完成(接口请求、DOM操作首选)
onMounted(() => console.log("挂载完成"));
// 更新前
onBeforeUpdate(() => console.log("更新前"));
// 更新完成
onUpdated(() => console.log("更新完成"));
// 销毁前
onBeforeUnmount(() => console.log("销毁前"));
// 销毁完成(清除定时器、监听)
onUnmounted(() => console.log("销毁完成"));
</script>
核心场景:onMounted 页面加载请求接口,onUnmounted 清除定时器、事件监听,防止内存泄漏。
五、Vue3 高阶核心特性
1. 跨层通信 provide / inject
解决多层父子组件嵌套传值繁琐问题,祖先组件注入数据,任意后代组件直接获取。
实战案例:祖孙组件跨层传值
<!-- 顶层父组件 -->
<script setup>
import { provide, ref } from 'vue';
import GrandSon from './components/GrandSon.vue';
// 提供数据
const theme = ref("深色主题");
provide("theme", theme);
</script>
<template>
<GrandSon />
</template>
<!-- 深层孙子组件 -->
<script setup>
import { inject } from 'vue';
// 注入数据,第二个参数为默认值
const theme = inject("theme", "默认主题");
</script>
<template>
<p>获取顶层主题:{{ theme }}</p>
</template>
2. KeepAlive 组件缓存
缓存组件实例,避免组件重复销毁重建,保留页面状态、提升性能,列表页、表单页常用。
<template>
<!-- 缓存内部组件 -->
<KeepAlive>
<component :is="currentComponent"></component>
</KeepAlive>
</template>
3. Teleport 瞬移组件
将组件DOM结构挂载到任意页面节点,不受父组件样式、层级限制,弹窗、模态框必备。
<template>
<button @click="show = true">打开弹窗</button>
<Teleport to="body">
<div v-if="show" class="modal">
<p>全局弹窗(挂载到body)</p>
<button @click="show = false">关闭</button>
</div>
</Teleport>
</template>
<script setup>
import { ref } from 'vue';
const show = ref(false);
</script>
<style scoped>
.modal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
padding: 20px;
background: #fff;
border: 1px solid #eee;
}
</style>
4. 自定义指令
封装通用DOM操作,全局复用,常用场景:按钮权限、自动聚焦、复制文本。
实战案例:自动聚焦指令
<template>
<input v-focus placeholder="页面自动聚焦">
</template>
<script setup>
// 自定义局部指令 v-focus
const vFocus = {
mounted(el) {
// 挂载后自动聚焦
el.focus();
}
};
</script>
5. nextTick 异步更新队列
Vue更新DOM是异步的,修改数据后无法立即获取最新DOM,nextTick可在DOM更新完成后执行回调。
<template>
<p ref="domRef">{{ text }}</p>
<button @click="changeText">修改文本</button>
</template>
<script setup>
import { ref, nextTick } from 'vue';
const text = ref("旧文本");
const domRef = ref(null);
const changeText = async () => {
text.value = "新文本";
// 此时DOM未更新,获取旧值
console.log("更新前:", domRef.value.innerText);
// 等待DOM更新完成
await nextTick();
// 获取最新DOM值
console.log("更新后:", domRef.value.innerText);
};
</script>
六、自定义Hooks封装(企业工程化必备)
Hooks是Vue3核心工程化思想,复用逻辑、剥离业务、代码解耦,替代Vue2混入。
实战案例:封装通用倒计时Hook
新建 src/hooks/useCountDown.js
import { ref } from 'vue';
export function useCountDown(initTime = 60) {
// 倒计时数值
const count = ref(0);
let timer = null;
// 开始倒计时
const start = () => {
count.value = initTime;
timer = setInterval(() => {
count.value--;
if (count.value <= 0) {
clearInterval(timer);
}
}, 1000);
};
return { count, start };
}
组件中使用
<template>
<button @click="start">
{{ count ? `${count}秒后重新获取` : "获取验证码" }}
</button>
</template>
<script setup>
// 引入自定义hook
import { useCountDown } from './hooks/useCountDown';
const { count, start } = useCountDown(60);
</script>
优势:逻辑完全复用,多个组件可直接调用,无需重复编写倒计时逻辑。