Skip to content

Vue 快速入门 ⭐ ​

了解 Vue 并搭建开发环境


学习目标 ​

  • 理解 Vue 是什么及核心特点
  • 搭建 Vue 开发环境
  • 创建第一个 Vue 组件
  • 掌握模板语法、条件渲染、列表渲染和事件处理

生活化比喻 ​

Vue 就像"智能装修队":

比喻对应:

┌──────────────────────────────────────────────────────┐
│                  智能装修队                           │
├──────────────────────────────────────────────────────┤
│                                                      │
│    传统 JS = 自己动手装修                             │
│    ─────────────                                     │
│    你要自己量尺寸、买材料、刷漆、接线                  │
│    每一步都要手动操作                                 │
│                                                      │
│    Vue = 请装修队 + 智能家居                          │
│    ─────────────                                     │
│    你只说"我要什么样的"(声明式)                    │
│    装修队自动帮你搞定所有细节                        │
│                                                      │
│    响应式 = 智能感应灯                                │
│    ─────────────                                     │
│    人来了自动亮,人走了自动灭                        │
│    你不需要手动开关                                   │
│                                                      │
│    组件 = 预制模块                                    │
│    ─────────────                                     │
│    厨房模块、卫生间模块、卧室模块                    │
│    每个模块独立,可以重复使用                        │
│                                                      │
│    单文件组件 = 一个房间的完整设计图                  │
│    ─────────────                                     │
│    结构(HTML)、样式(CSS)、功能(JS) 都在一张图上     │
│                                                      │
└──────────────────────────────────────────────────────┘

L1 理解层:会用 ​

Vue 基础 ​

最简示例:

vue
<script setup>
import { ref } from 'vue'
const message = ref('Hello Vue!')
</script>

<template>
  <h1>{{ message }}</h1>
  <button @click="message = 'Clicked!'">点击</button>
</template>

详细示例:

vue
<!-- src/main.js — 入口文件 -->
<script>
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
</script>
vue
<!-- src/App.vue — 单文件组件 -->
<script setup>
import { ref } from 'vue'

const message = ref('Hello Vue!')
const count = ref(0)

const handleClick = () => { count.value++ }
</script>

<template>
  <div class="app">
    <h1>{{ message }}</h1>
    <p>点击次数:{{ count }}</p>
    <button @click="handleClick">+1</button>
  </div>
</template>

<style scoped>
.app { padding: 20px; }
h1 { color: #42b883; }
</style>

模板语法 ​

语法结构图:

模板语法:

{{ 表达式 }}           → 文本插值
v-bind:attr="值"       → 属性绑定(简写 :attr)
v-on:click="方法"      → 事件绑定(简写 @click)
v-model="数据"         → 双向绑定
v-if / v-else / v-show → 条件渲染
v-for="item in 列表"   → 列表渲染

最简示例(1-3行):

vue
<template>
  <h1>{{ title }}</h1>
  <img :src="url" @click="handleClick">
  <input v-model="message">
</template>

详细示例:

vue
<template>
  <div>
    <!-- 插值:支持表达式 -->
    <p>{{ count + 1 }}</p>
    <p>{{ message.toUpperCase() }}</p>
    <p>{{ isActive ? '开' : '关' }}</p>

    <!-- 属性绑定 -->
    <img :src="imageUrl" :alt="title" />
    <div :class="{ active: isActive }">内容</div>
    <div :style="{ color: textColor }">内容</div>

    <!-- 双向绑定 -->
    <input v-model="message" />
    <input v-model.number="age" />   <!-- 自动转数字 -->
    <input v-model.trim="text" />    <!-- 自动去空格 -->

    <!-- 条件渲染 -->
    <div v-if="type === 'A'">A</div>
    <div v-else-if="type === 'B'">B</div>
    <div v-else>其他</div>
    <div v-show="isVisible">显示/隐藏</div>

    <!-- 列表渲染 -->
    <li v-for="item in items" :key="item.id">
      {{ item.name }}
    </li>
  </div>
</template>

<script setup>
import { ref } from 'vue'
const count = ref(5)
const message = ref('hello')
const isActive = ref(true)
const imageUrl = ref('photo.jpg')
const type = ref('A')
const isVisible = ref(true)
const items = ref([
  { id: 1, name: '苹果' },
  { id: 2, name: '香蕉' }
])
</script>

事件处理 ​

最简示例:

vue
<template>
  <button @click="count++">{{ count }}</button>
  <form @submit.prevent="handleSubmit">
    <button type="submit">提交</button>
  </form>
</template>

详细示例:

vue
<template>
  <div>
    <!-- 内联处理 -->
    <button @click="count++">+1</button>

    <!-- 方法调用 -->
    <button @click="handleClick('参数')">点击</button>

    <!-- 访问事件对象 -->
    <button @click="handleEvent($event)">点击</button>

    <!-- 常用修饰符 -->
    <form @submit.prevent="onSubmit"></form>      <!-- 阻止默认 -->
    <div @click.stop="onClick"></div>              <!-- 阻止冒泡 -->
    <button @click.once="onClick"></button>        <!-- 只一次 -->
    <input @keyup.enter="onEnter" />               <!-- 回车键 -->
  </div>
</template>

L2 实践层:用好 ​

v-if vs v-show 选择 ​

特性v-ifv-show
渲染方式条件为真才创建总是创建,切换 display
切换开销高低
适用场景条件很少改变频繁切换

反模式:不要这样做 ​

vue
<!-- ❌ 错误:用 index 作为 key(列表顺序变化时出问题) -->
<li v-for="(item, index) in items" :key="index">

<!-- ✅ 正确:用唯一 ID -->
<li v-for="item in items" :key="item.id">
vue
<!-- ❌ 错误:v-if 和 v-for 在同一元素上 -->
<li v-for="item in items" v-if="item.active">

<!-- ✅ 正确:用 computed 过滤或嵌套元素 -->
<template v-for="item in items" :key="item.id">
  <li v-if="item.active">{{ item.name }}</li>
</template>

适用场景 ​

场景推荐方案原因
表单输入v-model双向绑定最简洁
列表渲染v-for + 唯一 key高效更新 DOM
偶尔显示/隐藏v-if减少初始渲染
频繁切换v-showCSS 切换开销低
复杂属性绑定:class / :style动态样式

L3 专家层:深入 ​

响应式系统原理 ​

Vue 响应式工作流程:

1. 数据层:ref/reactive 通过 Proxy 拦截读写
2. 依赖收集:模板渲染时自动收集使用了哪些数据
3. 触发更新:数据变化时,重新渲染使用它的部分

响应式链:
  ref(0) → Proxy 代理 → 收集依赖 → 变化 → 触发更新 → 重新渲染

知识关联 ​

Vue 快速入门关联:

┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│  环境搭建   │────→│  模板语法   │────→│  事件处理   │
│  Vite/      │     │  插值/      │     │  @click/    │
│  SFC        │     │  绑定/      │     │  修饰符     │
└─────────────┘     │  条件/      │     └─────────────┘
                    │  列表       │
                    └─────────────┘
                           │
                           ↓
                    ┌─────────────┐
                    │  双向绑定   │
                    │  v-model    │
                    └─────────────┘

术语定义 ​

术语定义示例
SFC单文件组件,.vue 文件,包含 template/script/styleApp.vue
响应式数据变化时视图自动更新ref(0)
插值在模板中嵌入 JavaScript 表达式双花括号语法
指令以 v- 开头的特殊属性v-if, v-for, v-model
事件修饰符改变事件行为的后缀@click.stop, @submit.prevent
声明式描述"要什么"而非"怎么做"<div v-if="show">

实践练习 ​

练习:Todo 列表 ​

vue
<script setup>
import { ref } from 'vue'

const todos = ref([])
const newTodo = ref('')

const addTodo = () => {
  if (newTodo.value.trim()) {
    todos.value.push({
      id: Date.now(),
      text: newTodo.value,
      done: false
    })
    newTodo.value = ''
  }
}

const removeTodo = (id) => {
  todos.value = todos.value.filter(t => t.id !== id)
}

const remaining = () => todos.value.filter(t => !t.done).length
</script>

<template>
  <div>
    <h1>Todo 列表</h1>
    <form @submit.prevent="addTodo">
      <input v-model.trim="newTodo" placeholder="输入任务..." />
      <button type="submit">添加</button>
    </form>
    <ul>
      <li v-for="todo in todos" :key="todo.id">
        <input type="checkbox" v-model="todo.done" />
        <span :class="{ done: todo.done }">{{ todo.text }}</span>
        <button @click="removeTodo(todo.id)">删除</button>
      </li>
    </ul>
    <p v-if="todos.length">剩余:{{ remaining() }}</p>
  </div>
</template>

<style scoped>
.done { text-decoration: line-through; color: #999; }
</style>

常见问题 ​

Q1:Vue 2 和 Vue 3 有什么区别? ​

特性Vue 2Vue 3
响应式Object.definePropertyProxy
APIOptions APIComposition API(推荐)
TS 支持一般优秀
性能基准提升 1.5-2x

新项目直接用 Vue 3 + Composition API + <script setup>。

Q2:为什么 v-for 需要 key? ​

key 帮助 Vue 识别哪些元素变了,从而最小化 DOM 操作:

vue
<!-- ❌ 用 index 做 key,列表重排时会出错 -->
<li v-for="(item, i) in items" :key="i">

<!-- ✅ 用唯一 ID -->
<li v-for="item in items" :key="item.id">

Q3:ref 和 reactive 选哪个? ​

推荐优先用 ref,统一且灵活:

vue
<!-- ref:统一用 .value,可整体替换 -->
const count = ref(0)
count.value++

<!-- reactive:直接访问,但不能整体替换 -->
const user = reactive({ name: '张三' })
user.name = '李四'  // ✅
user = { name: '王五' }  // ❌ 丢失响应式

学习资源 ​