Vue 3 入门教程
目录
- 1. Vue 是什么
- 2. 第一个 Vue 项目
- 2.1 创建项目
- 2.2 启动项目
- 2.3 认识项目结构
- 3. 从官方"创建一个应用"理解 Vue 启动流程
- 4. 单文件组件
.vue - 5. 模板语法
- 5.1 文本插值
- 5.2 属性绑定
v-bind/: - 5.3 事件绑定
v-on/@
- 6. 响应式基础:
ref和reactive- 6.1
ref示例 - 6.2
reactive示例
- 6.1
- 7. 常用功能一:条件渲染
- 7.1
v-if/v-else-if/v-else - 7.2
v-show
- 7.1
- 8. 常用功能二:列表渲染
- 8.1 遍历数组
- 8.2 获取索引
- 9. 常用功能三:事件处理
- 9.1 基本事件
- 9.2 传参数
- 9.3 事件修饰符
- 10. 常用功能四:表单绑定
v-model - 11. 常用功能五:计算属性
computed - 12. 常用功能六:侦听器
watch - 13. 常用功能七:生命周期
- 14. 常用功能八:组件
- 14.1 创建组件
- 14.2 Props:父传子
- 14.3 Emits:子传父
- 14.4 插槽 slot
- 15. 常用功能九:模板引用
ref - 16. 常用功能十:样式绑定
- 16.1 class 绑定
- 16.2 style 绑定
- 17. 路由 Vue Router
- 17.1 基本概念
- 17.2 路由配置示例
- 17.3 动态路由
- 17.4 编程式导航
- 18. 状态管理 Pinia
- 18.1 注册 Pinia
- 18.2 创建 Store
- 19. 请求接口
- 19.1 fetch 示例
- 19.2 axios 示例
- 20. 常用项目功能怎么组合
- 20.1 登录功能
- 20.2 列表页
- 20.3 表单页
- 20.4 详情页
- 21. 新手常见问题
- 21.1 为什么 JS 里要写
.value - 21.2
ref和reactive怎么选 - 21.3 computed 和 watch 区别
- 21.1 为什么 JS 里要写
- 22. 最小记忆清单
1. Vue 是什么
Vue 是一个用于构建用户界面的 JavaScript 框架。它最常见的用途是开发前端页面、后台管理系统、单页应用、组件化页面和交互式业务系统。
Vue 的核心特点:
- 数据驱动界面:数据变了,页面自动更新。
- 组件化开发:把页面拆成一个个可复用组件。
- 模板语法简单:接近 HTML,容易上手。
- 官方生态完整:Vue Router 做路由,Pinia 做状态管理,Vite 做开发构建。
- 渐进式:可以从一个小页面开始,也可以做完整大型应用。
2. 第一个 Vue 项目
2.1 创建项目
在你想放项目的目录执行:
npmcreate vue@latest创建时会问你一些选项。新手建议:
Add TypeScript? No Add JSX Support? No Add Vue Router? Yes Add Pinia? Yes Add Vitest? No Add End-to-End Testing? No Add ESLint? Yes Add Prettier? Yes Add Vue DevTools? Yes如果你只是想先学 Vue 基础,也可以 Router 和 Pinia 都选 No,后面再加。
2.2 启动项目
cdyour-project-namenpminstallnpmrun dev浏览器打开终端提示的地址,通常是:
http://localhost:51732.3 认识项目结构
常见结构:
src/ main.js App.vue components/ views/ router/ stores/重点理解:
main.js:应用入口,创建 Vue 应用并挂载到页面。App.vue:根组件,整个应用的最外层组件。components/:通用组件。views/:页面级组件,通常配合路由使用。router/:路由配置。stores/:Pinia 状态管理。
3. 从官方“创建一个应用”理解 Vue 启动流程
Vue 应用通过createApp()创建应用实例,然后通过.mount()挂载到 HTML 容器。
典型入口:
import{createApp}from'vue'importAppfrom'./App.vue'constapp=createApp(App)app.mount('#app')对应index.html里通常有:
<divid="app"></div>理解这三个点:
createApp(App):用根组件创建 Vue 应用。App.vue:根组件,其他组件都挂在它下面。mount('#app'):把 Vue 应用渲染到页面里的#app容器。
注意:全局配置、插件注册、全局组件注册,一般要在mount()之前完成。
4. 单文件组件.vue
.vue文件是 Vue 的单文件组件,把模板、脚本、样式写在一个文件里,用<template>、<script>、<style>三个标签组织。
<script setup> import { ref } from 'vue' const message = ref('Hello Vue') </script> <template> <h1>{{ message }}</h1> </template> <style scoped> h1 { color: #42b883; } </style>含义:
<script setup>:写组件逻辑,变量和方法可直接在模板中使用。<template>:写页面结构,支持 Vue 模板语法。<style scoped>:写当前组件样式,scoped表示样式只影响当前组件,不影响其他组件。
新手重点:
- 一个
.vue文件就是一个组件。 - 组件名建议用大驼峰,比如
TodoList.vue。 - 页面复杂后,要主动拆组件,每个组件只负责一个功能。
5. 模板语法
Vue 模板基于 HTML,支持插值表达式{{ }}和指令(如v-bind、v-if)来绑定数据和逻辑。
5.1 文本插值
<script setup> const name = '小明' const count = 10 const isLogin = true </script> <template> <p>你好,{{ name }}</p> <p>{{ count + 1 }}</p> <p>{{ isLogin ? '已登录' : '未登录' }}</p> </template>{{ }}里可以写简单表达式,但不要在模板里写太复杂的逻辑,复杂逻辑放到计算属性或函数里。
5.2 属性绑定v-bind/:
<script setup> const imageUrl = '/logo.png' const title = 'Vue Logo' const disabled = true </script> <template> <img :src="imageUrl" :alt="title" /> <button :disabled="disabled">提交</button> </template>:是v-bind:的简写,用于动态绑定 HTML 属性。
5.3 事件绑定v-on/@
<script setup> function handleClick() { alert('点击了按钮') } </script> <template> <button @click="handleClick">点击我</button> </template>@click是v-on:click的简写,用于绑定事件监听。
6. 响应式基础:ref和reactive
ref用于基本类型和对象,取值需.value;reactive只用于对象,直接访问属性。两者都是响应式的,数据变化时视图自动更新。
6.1ref示例
<script setup> import { ref } from 'vue' const count = ref(0) const name = ref('小明') function add() { count.value++ } </script> <template> <p>{{ name }} 点击了 {{ count }} 次</p> <button @click="add">+1</button> </template>注意:
- 在 JS 里访问和修改 ref,要用
.value。 - 在模板里使用 ref,不需要写
.value,Vue 会自动解包。
6.2reactive示例
<script setup> import { reactive } from 'vue' const user = reactive({ name: '小明', age: 18 }) function birthday() { user.age++ } </script> <template> <p>{{ user.name }}:{{ user.age }} 岁</p> <button @click="birthday">过生日</button> </template>新手建议:
- 简单值用
ref。 - 表单对象、复杂对象用
reactive。 - 如果纠结,就优先用
ref,因为它更统一,且ref也可以放对象。
7. 常用功能一:条件渲染
v-if按条件渲染/销毁元素,v-show仅切换display属性。频繁切换用v-show,运行时条件少变用v-if。
7.1v-if/v-else-if/v-else
<script setup> import { ref } from 'vue' const score = ref(85) </script> <template> <p v-if="score >= 90">优秀</p> <p v-else-if="score >= 60">及格</p> <p v-else>不及格</p> </template>v-if是"真正的"条件渲染,条件为假时元素不会出现在 DOM 中。
7.2v-show
<script setup> import { ref } from 'vue' const visible = ref(true) </script> <template> <button @click="visible = !visible">切换显示</button> <p v-show="visible">这段内容可以显示或隐藏</p> </template>v-show只是切换 CSS 的display属性,元素始终在 DOM 中。
选择建议:
- 切换不频繁(如登录状态判断):用
v-if - 切换很频繁(如选项卡切换):用
v-show
8. 常用功能二:列表渲染
v-for遍历数组或对象,需绑定:key提升性能。格式:v-for="item in items" :key="item.id"。
8.1 遍历数组
<script setup> import { ref } from 'vue' const todos = ref([ { id: 1, text: '学习模板语法', done: true }, { id: 2, text: '学习列表渲染', done: false }, { id: 3, text: '写一个 Todo 项目', done: false } ]) </script> <template> <ul> <li v-for="todo in todos" :key="todo.id"> <span :style="{ textDecoration: todo.done ? 'line-through' : 'none' }"> {{ todo.text }} </span> </li> </ul> </template>8.2 获取索引
<template> <ul> <li v-for="(item, index) in items" :key="index"> {{ index + 1 }}. {{ item }} </li> </ul> </template>重点:
v-for用来循环数组或对象。- 必须写
:key,通常用后端 ID。 - 不建议用数组下标当 key,除非列表永远不排序、不删除、不插入。
9. 常用功能三:事件处理
9.1 基本事件
<button @click="submit">提交</button>functionsubmit(){console.log('提交')}9.2 传参数
<button @click="removeTodo(todo.id)">删除</button>functionremoveTodo(id){console.log(id)}9.3 事件修饰符
<form @submit.prevent="submitForm"> <button type="submit">提交</button> </form>常见修饰符:
.prevent:阻止默认行为。.stop:阻止冒泡。.once:只触发一次。.enter:监听回车键。
示例:
<input @keyup.enter="search" />11. 常用功能四:表单绑定v-model
v-model用来做双向绑定:输入框变,数据变;数据变,输入框也变。
<script setup> import { ref } from 'vue' const username = ref('') </script> <template> <input v-model="username" placeholder="请输入用户名" /> <p>你输入的是:{{ username }}</p> </template>常见表单:
<input v-model="text" /> <textarea v-model="content"></textarea> <input type="checkbox" v-model="checked" /> <select v-model="selected"> <option value="frontend">前端</option> <option value="backend">后端</option> </select>常用修饰符:
<input v-model.trim="name" /> <input v-model.number="age" /> <input v-model.lazy="message" />含义:
.trim:去掉首尾空格。.number:转成数字。.lazy:失焦或 change 时再更新。
12. 常用功能五:计算属性computed
计算属性用于根据已有数据派生新数据。
<script setup> import { ref, computed } from 'vue' const price = ref(100) const count = ref(2) const total = computed(() => price.value * count.value) </script> <template> <p>总价:{{ total }}</p> </template>什么时候用 computed:
- 根据一个或多个响应式数据计算出一个结果。
- 希望结果有缓存。
- 模板里的表达式变复杂了。
不要在 computed 里做:
- 发请求。
- 修改其他状态。
- 操作 DOM。
这些副作用应该放到watch、事件函数或生命周期里。
13. 常用功能六:侦听器watch
watch用于监听数据变化,然后执行副作用。
<script setup> import { ref, watch } from 'vue' const keyword = ref('') watch(keyword, (newValue, oldValue) => { console.log('搜索词变化了', oldValue, '->', newValue) }) </script> <template> <input v-model="keyword" placeholder="搜索" /> </template>常见用途:
- 搜索框输入变化后请求接口。
- 监听路由参数变化。
- 数据变化后写入 localStorage。
- 根据某个开关加载额外数据。
立即执行:
watch(keyword,()=>{// 初始化时执行一次,之后 keyword 变化也执行},{immediate:true})深度监听:
watch(()=>form,()=>{console.log('表单变化')},{deep:true})注意:深度监听复杂对象会有性能开销,不要滥用。
14. 常用功能七:生命周期
生命周期是组件从创建到销毁过程中可以插入逻辑的时机。
组合式 API 常用:
<script setup> import { onMounted, onUnmounted } from 'vue' onMounted(() => { console.log('组件已经挂载,可以请求接口或操作 DOM') }) onUnmounted(() => { console.log('组件卸载,清理定时器或事件监听') }) </script>常用钩子:
onMounted:组件挂载后,常用于请求初始数据。onUpdated:组件更新后。onUnmounted:组件卸载后,常用于清理资源。
新手重点掌握onMounted和onUnmounted即可。
15. 常用功能八:组件
组件是 Vue 项目的核心。
15.1 创建组件
src/components/UserCard.vue
<script setup> defineProps({ name: String, age: Number }) </script> <template> <div class="user-card"> <p>姓名:{{ name }}</p> <p>年龄:{{ age }}</p> </div> </template>在父组件使用:
<script setup> import UserCard from './components/UserCard.vue' </script> <template> <UserCard name="小明" :age="18" /> </template>15.2 Props:父传子
父组件:
<TodoItem :todo="todo" />子组件:
<script setup> defineProps({ todo: Object }) </script>15.3 Emits:子传父
子组件:
<script setup> const emit = defineEmits(['remove']) function handleClick() { emit('remove') } </script> <template> <button @click="handleClick">删除</button> </template>父组件:
<TodoItem @remove="removeTodo(todo.id)" />15.4 插槽 slot
插槽用于让父组件传入一段模板内容。
子组件:
<template> <div class="card"> <slot></slot> </div> </template>父组件:
<BaseCard> <h2>标题</h2> <p>内容</p> </BaseCard>常用组件拆分思路:
- 页面级组件放
views/。 - 可复用业务组件放
components/。 - 基础组件命名可以用
BaseButton.vue、BaseModal.vue。
16. 常用功能九:模板引用ref
有时候需要拿到 DOM 元素。
<script setup> import { ref, onMounted } from 'vue' const inputRef = ref(null) onMounted(() => { inputRef.value.focus() }) </script> <template> <input ref="inputRef" /> </template>常见用途:
- 自动聚焦输入框。
- 获取元素尺寸。
- 调用第三方库时传入 DOM。
不要过度使用 DOM 操作。Vue 推荐数据驱动界面。
17. 常用功能十:样式绑定
17.1 class 绑定
<div :class="{ active: isActive, error: hasError }"></div>数组写法:
<div :class="[baseClass, isActive ? 'active' : '']"></div>17.2 style 绑定
<div :style="{ color: textColor, fontSize: size + 'px' }"></div>实际项目建议:
- 大部分样式写 class。
- 少量动态数值用 style 绑定。
18. 路由 Vue Router
当项目有多个页面时,需要 Vue Router。
18.1 基本概念
- 路由:URL 和页面组件的对应关系。
router-link:页面跳转链接。router-view:当前路由页面显示的位置。
18.2 路由配置示例
src/router/index.js
import{createRouter,createWebHistory}from'vue-router'importHomeViewfrom'../views/HomeView.vue'importAboutViewfrom'../views/AboutView.vue'constrouter=createRouter({history:createWebHistory(),routes:[{path:'/',name:'home',component:HomeView},{path:'/about',name:'about',component:AboutView}]})exportdefaultroutersrc/main.js
import{createApp}from'vue'importAppfrom'./App.vue'importrouterfrom'./router'createApp(App).use(router).mount('#app')App.vue
<template> <nav> <RouterLink to="/">首页</RouterLink> <RouterLink to="/about">关于</RouterLink> </nav> <RouterView /> </template>18.3 动态路由
{path:'/users/:id',name:'user-detail',component:UserDetailView}组件里读取参数:
<script setup> import { useRoute } from 'vue-router' const route = useRoute() console.log(route.params.id) </script>18.4 编程式导航
<script setup> import { useRouter } from 'vue-router' const router = useRouter() function goHome() { router.push('/') } </script>常用场景:
- 登录成功后跳转首页。
- 保存表单后跳转详情页。
- 删除数据后返回列表页。
19. 状态管理 Pinia
当多个组件都要共享同一份数据时,可以使用 Pinia。
19.1 注册 Pinia
src/main.js
import{createApp}from'vue'import{createPinia}from'pinia'importAppfrom'./App.vue'constapp=createApp(App)app.use(createPinia())app.mount('#app')19.2 创建 Store
src/stores/user.js
import{defineStore}from'pinia'import{ref,computed}from'vue'exportconstuseUserStore=defineStore('user',()=>{consttoken=ref('')constname=ref('')constisLogin=computed(()=>Boolean(token.value))functionlogin(payload){token.value=payload.token name.value=payload.name}functionlogout(){token.value=''name.value=''}return{token,name,isLogin,login,logout}})组件中使用:
<script setup> import { useUserStore } from '@/stores/user' const userStore = useUserStore() </script> <template> <p v-if="userStore.isLogin">你好,{{ userStore.name }}</p> <button @click="userStore.logout">退出登录</button> </template>什么时候用 Pinia:
- 登录用户信息。
- token。
- 购物车。
- 全局主题。
- 多页面共享筛选条件。
- 复杂页面的共享状态。
什么时候不用:
- 只在一个组件内部使用的数据。
- 父子组件之间简单传值,优先 props/emit。
20. 请求接口
Vue 本身不规定请求库。新手可以先用fetch,项目里常用axios。
20.1 fetch 示例
<script setup> import { ref, onMounted } from 'vue' const list = ref([]) const loading = ref(false) const error = ref('') async function loadData() { loading.value = true error.value = '' try { const res = await fetch('/api/todos') list.value = await res.json() } catch (err) { error.value = '加载失败' } finally { loading.value = false } } onMounted(loadData) </script> <template> <p v-if="loading">加载中...</p> <p v-else-if="error">{{ error }}</p> <ul v-else> <li v-for="item in list" :key="item.id">{{ item.title }}</li> </ul> </template>20.2 axios 示例
安装:
npminstallaxios使用:
importaxiosfrom'axios'constres=awaitaxios.get('/api/todos')list.value=res.data建议封装src/api/:
src/api/ request.js user.js todo.js这样组件里不要散落很多 URL。
21. 常用项目功能怎么组合
21.1 登录功能
涉及:
- 表单
v-model - 点击事件
@click - 请求接口
- Pinia 存 token/user
- Vue Router 跳转
流程:
输入账号密码 -> 点击登录 -> 请求接口 -> 保存 token -> 跳转首页21.2 列表页
涉及:
onMounted请求数据v-for渲染列表v-if显示 loading/empty/error- 搜索框
v-model - 分页组件
流程:
进入页面 -> 请求列表 -> 展示数据 -> 搜索/分页 -> 重新请求21.3 表单页
涉及:
reactive表单对象v-model双向绑定- 表单校验
- 提交请求
- 成功后跳转
流程:
编辑表单 -> 校验 -> 提交接口 -> 成功提示 -> 返回列表21.4 详情页
涉及:
- 动态路由参数
useRouteonMounted- 请求详情接口
流程:
/users/1001 -> 读取 id -> 请求用户详情 -> 渲染页面22. 新手常见问题
22.1 为什么 JS 里要写.value
因为ref返回的是一个包装对象,真正的值在.value上。
constcount=ref(0)count.value++模板里 Vue 会自动解包:
<p>{{ count }}</p>22.2ref和reactive怎么选
简单规则:
- 数字、字符串、布尔值:
ref - 对象、表单:
reactive或ref - 不确定:先用
ref
22.3 computed 和 watch 区别
computed用来算值:
商品单价 + 数量 -> 总价watch用来做事情:
搜索词变化 -> 请求接口23. 最小记忆清单
必须记住:
createApp(App).mount('#app'):创建并挂载应用。.vue文件就是组件。ref创建响应式数据,JS 里用.value。{{ }}显示数据。:属性绑定属性。@事件绑定事件。v-if控制是否渲染。v-for渲染列表,必须写:key。v-model表单双向绑定。computed算派生值。watch监听变化做副作用。- props 父传子,emit 子传父。
- Router 管页面,Pinia 管全局状态。
