目录
- [1. Vue 是什么](#1. Vue 是什么)
- [2. 第一个 Vue 项目](#2. 第一个 Vue 项目)
- [2.1 创建项目](#2.1 创建项目)
- [2.2 启动项目](#2.2 启动项目)
- [2.3 认识项目结构](#2.3 认识项目结构)
- [3. 从官方"创建一个应用"理解 Vue 启动流程](#3. 从官方"创建一个应用"理解 Vue 启动流程)
- [4. 单文件组件
.vue](#4. 单文件组件 .vue) - [5. 模板语法](#5. 模板语法)
- [5.1 文本插值](#5.1 文本插值)
- [5.2 属性绑定
v-bind/:](#5.2 属性绑定 v-bind / :) - [5.3 事件绑定
v-on/@](#5.3 事件绑定 v-on / @)
- [6. 响应式基础:
ref和reactive](#6. 响应式基础:ref 和 reactive)- [6.1
ref示例](#6.1 ref 示例) - [6.2
reactive示例](#6.2 reactive 示例)
- [6.1
- [7. 常用功能一:条件渲染](#7. 常用功能一:条件渲染)
- [7.1
v-if/v-else-if/v-else](#7.1 v-if / v-else-if / v-else) - [7.2
v-show](#7.2 v-show)
- [7.1
- [8. 常用功能二:列表渲染](#8. 常用功能二:列表渲染)
- [8.1 遍历数组](#8.1 遍历数组)
- [8.2 获取索引](#8.2 获取索引)
- [9. 常用功能三:事件处理](#9. 常用功能三:事件处理)
- [9.1 基本事件](#9.1 基本事件)
- [9.2 传参数](#9.2 传参数)
- [9.3 事件修饰符](#9.3 事件修饰符)
- [10. 常用功能四:表单绑定
v-model](#10. 常用功能四:表单绑定 v-model) - [11. 常用功能五:计算属性
computed](#11. 常用功能五:计算属性 computed) - [12. 常用功能六:侦听器
watch](#12. 常用功能六:侦听器 watch) - [13. 常用功能七:生命周期](#13. 常用功能七:生命周期)
- [14. 常用功能八:组件](#14. 常用功能八:组件)
- [14.1 创建组件](#14.1 创建组件)
- [14.2 Props:父传子](#14.2 Props:父传子)
- [14.3 Emits:子传父](#14.3 Emits:子传父)
- [14.4 插槽 slot](#14.4 插槽 slot)
- [15. 常用功能九:模板引用
ref](#15. 常用功能九:模板引用 ref) - [16. 常用功能十:样式绑定](#16. 常用功能十:样式绑定)
- [16.1 class 绑定](#16.1 class 绑定)
- [16.2 style 绑定](#16.2 style 绑定)
- [17. 路由 Vue Router](#17. 路由 Vue Router)
- [17.1 基本概念](#17.1 基本概念)
- [17.2 路由配置示例](#17.2 路由配置示例)
- [17.3 动态路由](#17.3 动态路由)
- [17.4 编程式导航](#17.4 编程式导航)
- [18. 状态管理 Pinia](#18. 状态管理 Pinia)
- [18.1 注册 Pinia](#18.1 注册 Pinia)
- [18.2 创建 Store](#18.2 创建 Store)
- [19. 请求接口](#19. 请求接口)
- [19.1 fetch 示例](#19.1 fetch 示例)
- [19.2 axios 示例](#19.2 axios 示例)
- [20. 常用项目功能怎么组合](#20. 常用项目功能怎么组合)
- [20.1 登录功能](#20.1 登录功能)
- [20.2 列表页](#20.2 列表页)
- [20.3 表单页](#20.3 表单页)
- [20.4 详情页](#20.4 详情页)
- [21. 新手常见问题](#21. 新手常见问题)
- [21.1 为什么 JS 里要写
.value](#21.1 为什么 JS 里要写 .value) - [21.2
ref和reactive怎么选](#21.2 ref 和 reactive 怎么选) - [21.3 computed 和 watch 区别](#21.3 computed 和 watch 区别)
- [21.1 为什么 JS 里要写
- [22. 最小记忆清单](#22. 最小记忆清单)
1. Vue 是什么
Vue 是一个用于构建用户界面的 JavaScript 框架。它最常见的用途是开发前端页面、后台管理系统、单页应用、组件化页面和交互式业务系统。
Vue 的核心特点:
- 数据驱动界面:数据变了,页面自动更新。
- 组件化开发:把页面拆成一个个可复用组件。
- 模板语法简单:接近 HTML,容易上手。
- 官方生态完整:Vue Router 做路由,Pinia 做状态管理,Vite 做开发构建。
- 渐进式:可以从一个小页面开始,也可以做完整大型应用。
2. 第一个 Vue 项目
2.1 创建项目
在你想放项目的目录执行:
bash
npm create vue@latest
创建时会问你一些选项。新手建议:
text
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 启动项目
bash
cd your-project-name
npm install
npm run dev
浏览器打开终端提示的地址,通常是:
text
http://localhost:5173
2.3 认识项目结构
常见结构:
text
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 容器。
典型入口:
js
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
app.mount('#app')
对应 index.html 里通常有:
html
<div id="app"></div>
理解这三个点:
createApp(App):用根组件创建 Vue 应用。App.vue:根组件,其他组件都挂在它下面。mount('#app'):把 Vue 应用渲染到页面里的#app容器。
注意:全局配置、插件注册、全局组件注册,一般要在 mount() 之前完成。
4. 单文件组件 .vue
.vue 文件是 Vue 的单文件组件,把模板、脚本、样式写在一个文件里,用 <template>、<script>、<style> 三个标签组织。
vue
<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 文本插值
vue
<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 / :
vue
<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 / @
vue
<script setup>
function handleClick() {
alert('点击了按钮')
}
</script>
<template>
<button @click="handleClick">点击我</button>
</template>
@click 是 v-on:click 的简写,用于绑定事件监听。
6. 响应式基础:ref 和 reactive
ref 用于基本类型和对象,取值需 .value;reactive 只用于对象,直接访问属性。两者都是响应式的,数据变化时视图自动更新。
6.1 ref 示例
vue
<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.2 reactive 示例
vue
<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.1 v-if / v-else-if / v-else
vue
<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.2 v-show
vue
<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 遍历数组
vue
<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 获取索引
vue
<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 基本事件
vue
<button @click="submit">提交</button>
js
function submit() {
console.log('提交')
}
9.2 传参数
vue
<button @click="removeTodo(todo.id)">删除</button>
js
function removeTodo(id) {
console.log(id)
}
9.3 事件修饰符
vue
<form @submit.prevent="submitForm">
<button type="submit">提交</button>
</form>
常见修饰符:
.prevent:阻止默认行为。.stop:阻止冒泡。.once:只触发一次。.enter:监听回车键。
示例:
vue
<input @keyup.enter="search" />
11. 常用功能四:表单绑定 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>
常见表单:
vue
<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>
常用修饰符:
vue
<input v-model.trim="name" />
<input v-model.number="age" />
<input v-model.lazy="message" />
含义:
.trim:去掉首尾空格。.number:转成数字。.lazy:失焦或 change 时再更新。
12. 常用功能五:计算属性 computed
计算属性用于根据已有数据派生新数据。
vue
<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 用于监听数据变化,然后执行副作用。
vue
<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。
- 根据某个开关加载额外数据。
立即执行:
js
watch(keyword, () => {
// 初始化时执行一次,之后 keyword 变化也执行
}, { immediate: true })
深度监听:
js
watch(
() => form,
() => {
console.log('表单变化')
},
{ deep: true }
)
注意:深度监听复杂对象会有性能开销,不要滥用。
14. 常用功能七:生命周期
生命周期是组件从创建到销毁过程中可以插入逻辑的时机。
组合式 API 常用:
vue
<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
vue
<script setup>
defineProps({
name: String,
age: Number
})
</script>
<template>
<div class="user-card">
<p>姓名:{{ name }}</p>
<p>年龄:{{ age }}</p>
</div>
</template>
在父组件使用:
vue
<script setup>
import UserCard from './components/UserCard.vue'
</script>
<template>
<UserCard name="小明" :age="18" />
</template>
15.2 Props:父传子
父组件:
vue
<TodoItem :todo="todo" />
子组件:
vue
<script setup>
defineProps({
todo: Object
})
</script>
15.3 Emits:子传父
子组件:
vue
<script setup>
const emit = defineEmits(['remove'])
function handleClick() {
emit('remove')
}
</script>
<template>
<button @click="handleClick">删除</button>
</template>
父组件:
vue
<TodoItem @remove="removeTodo(todo.id)" />
15.4 插槽 slot
插槽用于让父组件传入一段模板内容。
子组件:
vue
<template>
<div class="card">
<slot></slot>
</div>
</template>
父组件:
vue
<BaseCard>
<h2>标题</h2>
<p>内容</p>
</BaseCard>
常用组件拆分思路:
- 页面级组件放
views/。 - 可复用业务组件放
components/。 - 基础组件命名可以用
BaseButton.vue、BaseModal.vue。
16. 常用功能九:模板引用 ref
有时候需要拿到 DOM 元素。
vue
<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 绑定
vue
<div :class="{ active: isActive, error: hasError }"></div>
数组写法:
vue
<div :class="[baseClass, isActive ? 'active' : '']"></div>
17.2 style 绑定
vue
<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
js
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
import AboutView from '../views/AboutView.vue'
const router = createRouter({
history: createWebHistory(),
routes: [
{ path: '/', name: 'home', component: HomeView },
{ path: '/about', name: 'about', component: AboutView }
]
})
export default router
src/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>
<nav>
<RouterLink to="/">首页</RouterLink>
<RouterLink to="/about">关于</RouterLink>
</nav>
<RouterView />
</template>
18.3 动态路由
js
{ path: '/users/:id', name: 'user-detail', component: UserDetailView }
组件里读取参数:
vue
<script setup>
import { useRoute } from 'vue-router'
const route = useRoute()
console.log(route.params.id)
</script>
18.4 编程式导航
vue
<script setup>
import { useRouter } from 'vue-router'
const router = useRouter()
function goHome() {
router.push('/')
}
</script>
常用场景:
- 登录成功后跳转首页。
- 保存表单后跳转详情页。
- 删除数据后返回列表页。
19. 状态管理 Pinia
当多个组件都要共享同一份数据时,可以使用 Pinia。
19.1 注册 Pinia
src/main.js
js
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
const app = createApp(App)
app.use(createPinia())
app.mount('#app')
19.2 创建 Store
src/stores/user.js
js
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
export const useUserStore = defineStore('user', () => {
const token = ref('')
const name = ref('')
const isLogin = computed(() => Boolean(token.value))
function login(payload) {
token.value = payload.token
name.value = payload.name
}
function logout() {
token.value = ''
name.value = ''
}
return {
token,
name,
isLogin,
login,
logout
}
})
组件中使用:
vue
<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 示例
vue
<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 示例
安装:
bash
npm install axios
使用:
js
import axios from 'axios'
const res = await axios.get('/api/todos')
list.value = res.data
建议封装 src/api/:
text
src/api/
request.js
user.js
todo.js
这样组件里不要散落很多 URL。
21. 常用项目功能怎么组合
21.1 登录功能
涉及:
- 表单
v-model - 点击事件
@click - 请求接口
- Pinia 存 token/user
- Vue Router 跳转
流程:
text
输入账号密码 -> 点击登录 -> 请求接口 -> 保存 token -> 跳转首页
21.2 列表页
涉及:
onMounted请求数据v-for渲染列表v-if显示 loading/empty/error- 搜索框
v-model - 分页组件
流程:
text
进入页面 -> 请求列表 -> 展示数据 -> 搜索/分页 -> 重新请求
21.3 表单页
涉及:
reactive表单对象v-model双向绑定- 表单校验
- 提交请求
- 成功后跳转
流程:
text
编辑表单 -> 校验 -> 提交接口 -> 成功提示 -> 返回列表
21.4 详情页
涉及:
- 动态路由参数
useRouteonMounted- 请求详情接口
流程:
text
/users/1001 -> 读取 id -> 请求用户详情 -> 渲染页面
22. 新手常见问题
22.1 为什么 JS 里要写 .value
因为 ref 返回的是一个包装对象,真正的值在 .value 上。
js
const count = ref(0)
count.value++
模板里 Vue 会自动解包:
vue
<p>{{ count }}</p>
22.2 ref 和 reactive 怎么选
简单规则:
- 数字、字符串、布尔值:
ref - 对象、表单:
reactive或ref - 不确定:先用
ref
22.3 computed 和 watch 区别
computed 用来算值:
text
商品单价 + 数量 -> 总价
watch 用来做事情:
text
搜索词变化 -> 请求接口
23. 最小记忆清单
必须记住:
createApp(App).mount('#app'):创建并挂载应用。.vue文件就是组件。ref创建响应式数据,JS 里用.value。{``{ }}显示数据。:属性绑定属性。@事件绑定事件。v-if控制是否渲染。v-for渲染列表,必须写:key。v-model表单双向绑定。computed算派生值。watch监听变化做副作用。- props 父传子,emit 子传父。
- Router 管页面,Pinia 管全局状态。