这是一份从零基础到能独立开发项目的完整 Vue 3 教程。
这个教程假设你有 HTML、CSS 和 JavaScript(ES6+)基础。如果没有,先补齐这些。
教程分为四个阶段:入门基础、核心概念、进阶工具、项目实践。
全程使用组合式 API(Vue 3 推荐风格),因为它更灵活。每个部分有代码示例、解释和练习。
学习建议:
- 用 Vite 创建项目(npm create vue@latest),边学边敲代码。
- 官方文档:https://cn.vuejs.org/(随时查阅)。
- 时间估计:入门 2-3 天,核心 3-5 天,进阶 2-3 天,项目 1 周。
- 环境:Node.js 18+,VS Code 编辑器(安装 Volar 插件)。
阶段 1: 入门基础(快速上手)
目标:创建第一个应用,理解 Vue 的核心——响应式和模板。
1.1 安装与项目创建
- 用 Vite 创建项目(推荐,热重载快):
npm create vue@latest my-vue-app
cd my-vue-app
npm install
npm run dev
选择:Yes(TypeScript?No,先基础);Yes(JSX?No);Yes(Router?稍后);Yes(Pinia?稍后);No(Vitest?稍后);No(ESLint?稍后)。
- 目录结构:
my-vue-app/
├── src/
│ ├── components/ # 组件
│ ├── App.vue # 根组件
│ └── main.js # 入口
├── public/ # 静态资源
└── package.json
练习:运行 npm run dev,浏览器打开 http://localhost:5173,看到默认页面。
1.2 第一个应用:Hello World
编辑 src/App.vue:
<template>
<div>
<h1>{{ message }}</h1>
<button @click="updateMessage">更新消息</button>
</div>
</template>
<script setup>
import { ref } from 'vue';
const message = ref('Hello Vue 3!'); // 响应式变量
const updateMessage = () => {
message.value = '消息已更新!'; // 更新数据,UI 自动刷新
};
</script>
<style>
h1 { color: blue; }
</style>
- 解释:
- <template>:HTML 模板,{{ }} 插值。
- <script setup>:组合式 API 的简洁语法,自动暴露变量/函数到模板。
- ref():创建响应式引用,.value 访问/修改值。
- @click:事件绑定。
- <style>:组件样式(默认全局,加 scoped 限制范围)。
练习:添加一个输入框,用 v-model 双向绑定 message。
1.3 模板语法基础
- 文本插值:{{ expression }}(如 {{ count + 1 }})。
- 属性绑定::src=”imageUrl”(v-bind 缩写)。
- 条件渲染:
<p v-if="isVisible">显示内容</p>
<p v-else>隐藏内容</p>
<template v-for="item in items" :key="item.id">
<li>{{ item.name }}</li>
</template>
- 事件与方法:@click=”handler($event)”,$event 是事件对象。
练习:构建一个列表,渲染 3 个物品,用按钮切换显示/隐藏。
阶段 2: 核心概念(构建组件化应用)
目标:掌握组件、数据流和生命周期。
2.1 组件创建与通信
组件是 Vue 的核心:可复用 UI 块。
- 创建组件:新建 src/components/Counter.vue:
<template>
<div>
<p>计数:{{ count }}</p>
<button @click="$emit('increment')">+1</button>
</div>
</template>
<script setup>
import { ref } from 'vue';
defineProps(['initialValue']); // 接收父组件 props
defineEmits(['increment']); // 声明事件
const count = ref(0);
</script>
- 在父组件使用(App.vue)
<template>
<Counter :initial-value="5" @increment="handleIncrement" />
<p>父组件计数:{{ parentCount }}</p>
</template>
<script setup>
import { ref } from 'vue';
import Counter from './components/Counter.vue';
const parentCount = ref(0);
const handleIncrement = () => {
parentCount.value++;
};
</script>
解释:
- defineProps():接收数据(单向流动)。
- defineEmits():子向父通信。
- :initial-value:props 绑定(响应式)。
插槽(Slots):组件内容分发。
<!-- 子组件 -->
<template>
<div>
<slot name="header"></slot> <!-- 默认插槽 -->
<slot></slot> <!-- 具名插槽 -->
</div>
</template>
<!-- 父使用 -->
<MyCard>
<template #header>标题</template>
<p>内容</p>
</MyCard>
练习:创建一个 TodoItem 组件,接收任务文本作为 props,用插槽自定义按钮。
2.2 响应式与计算属性
ref vs reactive:
- ref(primitive):基本类型(如 string、number)。
- reactive(object):对象/数组(无需 .value)。
<script setup>
import { ref, reactive, computed } from 'vue';
const count = ref(0);
const user = reactive({ name: '张三', age: 25 });
const doubled = computed(() => count.value * 2); // 计算属性,缓存优化
const fullName = computed(() => `${user.name} - ${user.age}岁`);
</script>
- 监听器:watch(() => count.value, (newVal) => { … })。
练习:用 computed 计算 Todo 列表的完成率。
2.3 生命周期钩子
Vue 组件有 8 个钩子(组合式 API 用 onXxx):
| 钩子 | 时机 | 用例 |
| onBeforeMount | 模板编译前 | 准备数据 |
| onMounted | 挂载后 | 发送 AJAX、DOM 操作 |
| onUpdated | 数据更新后 | 响应变化 |
| onUnmounted | 卸载前 | 清理资源 |
示例:
<script setup>
import { onMounted, onUnmounted } from 'vue';
let timer;
onMounted(() => {
timer = setInterval(() => console.log('tick'), 1000);
});
onUnmounted(() => clearInterval(timer));
</script>
练习:在组件挂载时从 localStorage 加载数据,卸载时保存。
阶段 3: 进阶工具(构建真实应用)
目标:集成路由、状态管理和优化。
3.1 Vue Router(路由)
安装:npm install vue-router@4。
- 配置 src/router/index.js:
import { createRouter, createWebHistory } from 'vue-router';
import Home from '../views/Home.vue';
import About from '../views/About.vue';
const routes = [
{ path: '/', component: Home },
{ path: '/about', component: About }
];
export default createRouter({
history: createWebHistory(),
routes
});
- 在 main.js:
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
createApp(App).use(router).mount('#app');
- 使用:<router-view />(渲染组件),<router-link to=”/about”>关于</router-link>。
练习:添加动态路由 /user/:id,用 params 获取 ID。
3.2 状态管理:Pinia
安装:npm install pinia。
- 创建 Store src/stores/counter.js:
import { defineStore } from 'pinia';
import { ref } from 'vue';
export const useCounterStore = defineStore('counter', () => {
const count = ref(0);
const increment = () => count.value++;
return { count, increment };
});
- 使用
<script setup>
import { useCounterStore } from '../stores/counter';
const store = useCounterStore();
</script>
<template>
<p>{{ store.count }}</p>
<button @click="store.increment">+1</button>
</template>
- 在 main.js:app.use(createPinia())。
练习:用 Pinia 管理全局 Todo 列表(添加/删除)。
3.3 构建与部署
- 开发:npm run dev。
- 构建:npm run build(生成 dist/ 文件夹)。
- 部署:上传到 Vercel/Netlify,或用 serve -s dist 本地预览。
- 优化:用 vite.config.js 配置代理、插件。
练习:构建项目,部署到 GitHub Pages。
阶段 4: 项目实践(Todo App)
目标:整合所有知识,构建一个完整 Todo 应用(带路由、状态管理)。
项目概述
- 功能:添加/编辑/删除任务,标记完成,路由切换(首页/详情),持久化(localStorage)。
- 架构:
- App.vue:路由入口。
- views/Home.vue:Todo 列表。
- components/TodoItem.vue:单个任务。
- stores/todos.js:状态管理。
步骤 1: 设置项目
用 Vite 创建,安装 Router 和 Pinia。
步骤 2: 创建 Store(stores/todos.js)
import { defineStore } from 'pinia';
import { ref } from 'vue';
export const useTodosStore = defineStore('todos', () => {
const todos = ref([]); // { id, text, completed }
const addTodo = (text) => {
todos.value.push({ id: Date.now(), text, completed: false });
};
const toggleTodo = (id) => {
const todo = todos.value.find(t => t.id === id);
if (todo) todo.completed = !todo.completed;
};
const deleteTodo = (id) => {
todos.value = todos.value.filter(t => t.id !== id);
};
// 持久化
const saveToLocal = () => localStorage.setItem('todos', JSON.stringify(todos.value));
const loadFromLocal = () => {
const saved = localStorage.getItem('todos');
if (saved) todos.value = JSON.parse(saved);
};
return { todos, addTodo, toggleTodo, deleteTodo, saveToLocal, loadFromLocal };
});
步骤 3: TodoItem 组件(components/TodoItem.vue)
<template>
<li :class="{ completed: todo.completed }">
<input type="checkbox" v-model="todo.completed" @change="$emit('toggle', todo.id)" />
<span>{{ todo.text }}</span>
<button @click="$emit('delete', todo.id)">删除</button>
</li>
</template>
<script setup>
defineProps(['todo']);
defineEmits(['toggle', 'delete']);
</script>
<style scoped>
.completed { text-decoration: line-through; }
li { display: flex; gap: 10px; }
</style>
步骤 4: Home 视图(views/Home.vue)
<template>
<div>
<h1>我的 Todo 列表</h1>
<input v-model="newTodo" @keyup.enter="addTodo" placeholder="添加任务" />
<ul>
<TodoItem v-for="todo in store.todos" :key="todo.id" :todo="todo" @toggle="store.toggleTodo" @delete="store.deleteTodo" />
</ul>
</div>
</template>
<script setup>
import { ref } from 'vue';
import { useTodosStore } from '../stores/todos';
import TodoItem from '../components/TodoItem.vue';
const store = useTodosStore();
const newTodo = ref('');
const addTodo = () => {
if (newTodo.value.trim()) {
store.addTodo(newTodo.value);
store.saveToLocal();
newTodo.value = '';
}
};
store.loadFromLocal(); // 加载数据
</script>
步骤 5: 路由与 App(router/index.js 和 App.vue)
- Router 如 3.1 节,添加 { path: ‘/’, component: Home }。
- App.vue:
<template>
<router-view />
</template>
<script setup>
import { onMounted } from 'vue';
import { useTodosStore } from './stores/todos';
onMounted(() => {
const store = useTodosStore();
store.loadFromLocal();
window.addEventListener('beforeunload', () => store.saveToLocal());
});
</script>
步骤 6: 测试与扩展
- 运行 npm run dev,添加/操作任务,刷新页面数据保留。
- 扩展:
- 添加编辑功能(用 input 替换 span)。
- 路由到任务详情页(/todo/:id)。
- 用 Axios 连接后端 API(安装 npm i axios)。
练习:完成项目后,添加过滤(未完成/所有),部署到 Vercel。
如果你坚持学到现在,那么恭喜你,你已经可以使用VUE来开发中型项目了
接下来通过所学知识以及查阅资料完成以下内容:
TypeScript:重启项目选 Yes,类型安全。
测试:用 Vitest(npm i -D vitest),写单元测试。
UI 库:Element Plus 或 Ant Design Vue。
真实项目:博客系统、电商列表(用 GitHub 托管)。
勤加练习,坚持实践,下一个百万年薪程序员就是你了!








