Vue 3 核心教程

从「改 DOM」到「改数据」— 给中际旭创全栈工程师的 Vue 3 入门实战手册

01 · Vue 是什么

想象你在工厂里做一个 设备状态看板。传统做法(jQuery)就像手动写白板:

Vue = 自动白板:你只需要把数据改掉(比如 status = '停机'),白板上的字自动变化。你不用关心「怎么改 DOM」,只管「改数据」。

🏭 工厂类比

jQuery = 你是车间工人,每次设备状态变化,你得亲自跑过去改看板上的字。
Vue = 你是 MES 系统,只管更新数据库里的状态,看板会自动刷新。

📊 Excel 类比
概念ExcelVue
数据A1 单元格的值ref(85) 响应式变量
视图B1 的公式 =A1*2模板中的 {{ value * 2 }}
更新改 A1 → B1 自动变改 ref → 页面自动变
核心思想数据驱动公式数据驱动视图

jQuery vs Vue 代码对比

jQuery:手动操作 DOM jQuery
// 数据变了,你手动找到元素,手动更新文字
var oee = 85;
$('#oee-value').text(oee);          // 手动改 DOM
$('#oee-bar').css('width', oee + '%'); // 手动改样式

// 数据又变了?再来一遍!
oee = 72;
$('#oee-value').text(oee);
$('#oee-bar').css('width', oee + '%');
Vue:只管数据,DOM 自动更新 Vue 3
const oee = ref(85)

// 模板里用 {{ oee }},页面自动显示 85
// 数据一改,页面自动更新,不用碰 DOM!
oee.value = 72  // 就这一行,页面自动变了
💡 一句话总结

Vue 的核心思想 = 数据驱动视图。你只管改数据,页面自动更新。就像 Excel 里改了源单元格,所有引用它的公式都会自动重算。

02 · 响应式数据 (ref / reactive)

响应式 是 Vue 的灵魂。简单说就是:数据一变,页面自动更新

Vue 3 提供两种方式创建响应式数据:

ref — 包裹单个值

基本用法 Vue 3
import { ref } from 'vue'

// 创建一个响应式变量,初始值 85
const oee = ref(85)

// 读取:用 .value
console.log(oee.value)  // 85

// 修改:也用 .value → 页面自动更新
oee.value = 92
✅ 页面渲染结果

OEE 当前值:92(数据从 85 变成 92 后,页面自动更新)

reactive — 包裹整个对象

对象/字典的响应式 Vue 3
import { reactive } from 'vue'

// 创建一个响应式对象(像 Excel 的一行数据)
const machine = reactive({
  name: 'CNC-A01',
  status: '运行中',
  oee: 85,
  output: 1200
})

// reactive 不需要 .value,直接访问属性
machine.status = '停机'  // 页面自动更新
machine.oee = 0
✅ 页面渲染结果

设备:CNC-A01  |  状态:停机  |  OEE:0%  |  产量:1200

ref vs reactive 对比

📊 Excel 类比
Excel 类比refreactive
适合场景单个单元格单个值(数字、字符串)整行数据(对象)
访问方式=A1oee.value(JS 中要 .value)machine.oee(直接用)
模板中使用直接引用{{ oee }}(自动解包){{ machine.oee }}
特性refreactive
数据类型任意(数字、字符串、布尔、对象都行)仅对象 / 数组
JS 中读取x.valuex.prop
模板中使用{{ x }}(自动解包){{ x.prop }}
重新赋值x.value = 新值❌ 不能整个替换,只能改属性
推荐场景基础值、单个状态表单、复杂对象
⚠️ 常见坑

ref 在 JS 中必须用 .value,但在模板中会自动解包,不需要 .value。这是新手最容易忘的!

reactive 不能整个替换对象machine = { ... } 会丢失响应性,必须逐个属性改。

03 · 模板语法

Vue 的模板就是 增强版 HTML,在普通 HTML 基础上加了几个「魔法指令」。

🏭 工厂类比

模板 = 看板的「版式模板」。你定好版式(哪里放设备名、哪里放状态灯),数据填进去就自动显示。不用每次重画整个看板。

3.1 插值 {{ }}

{{ }} = 在 HTML 中显示数据,就像 Excel 的 =A1

模板插值 Vue 3
<template>
  <div>
    <h2>{{ machineName }}</h2>
    <p>OEE: {{ oee }}%</p>
    <p>状态: {{ status === 'running' ? '运行中' : '停机' }}</p>
  </div>
</template>

<script setup>
const machineName = ref('CNC-A01')
const oee = ref(87.5)
const status = ref('running')
</script>
✅ 渲染结果

CNC-A01

OEE: 87.5%

状态: 运行中

3.2 v-bind — 绑定属性

v-bind = 把数据绑定到 HTML 属性上,简写为 :。就像 Excel 的「单元格链接」。

属性绑定 Vue 3
<!-- 完整写法 -->
<img v-bind:src="imageUrl" v-bind:alt="machineName" />

<!-- 简写(推荐,日常都用这个) -->
<img :src="imageUrl" :alt="machineName" />

<!-- 实际案例:动态进度条 -->
<div class="progress-bar"
     :style="{ width: oee + '%' }">
  {{ oee }}%
</div>

<!-- 动态 class -->
<span :class="{ 'text-green': status === 'running', 'text-red': status !== 'running' }">
  {{ status }}
</span>
✅ 渲染结果

动态进度条:

87%
● 运行中

3.3 v-on — 绑定事件

v-on = 监听用户操作(点击、输入等),简写为 @

📊 Excel 类比
ExcelVue
按钮 → 运行宏@click → 调用函数
数据验证 → 触发提示@change → 响应变化
事件绑定 Vue 3
<template>
  <!-- 完整写法 -->
  <button v-on:click="refreshData">刷新数据</button>

  <!-- 简写(推荐) -->
  <button @click="refreshData">刷新数据</button>

  <!-- 带参数 -->
  <button @click="selectMachine('CNC-A01')">选择 A01</button>

  <!-- 实时计数器 -->
  <p>已刷新 {{ count }} 次</p>
  <button @click="count++">+1</button>
</template>

<script setup>
const count = ref(0)
const refreshData = () => {
  count.value++
  console.log('数据已刷新')
}
const selectMachine = (id) => {
  console.log('选中:', id)
}
</script>

3.4 v-model — 双向绑定

v-model = 数据 ↔ 视图双向同步。你改输入框,数据跟着变;你改数据,输入框也变。

🏭 工厂类比

想象一个「设备筛选搜索框」:你在搜索框输入"CNC",筛选结果实时跟着变。这就是 v-model — 输入框和数据之间有根看不见的线,两头同步。

双向绑定 Vue 3
<template>
  <input v-model="searchText" placeholder="搜索设备..." />
  <p>搜索关键词: {{ searchText }}</p>

  <!-- 也可用于 select -->
  <select v-model="selectedLine">
    <option value="line1">产线 1</option>
    <option value="line2">产线 2</option>
  </select>
</template>

<script setup>
const searchText = ref('')
const selectedLine = ref('line1')
</script>
✅ 渲染结果(用户输入"CNC"后)

搜索关键词: CNC

3.5 v-if / v-show — 条件渲染

v-ifv-show
原理真正销毁/创建 DOM 元素只是 CSS display: none 切换
切换开销高(每次重建 DOM)低(只改 CSS)
初始开销低(条件为 false 不渲染)高(始终渲染)
适用场景不频繁切换(弹窗、权限)频繁切换(Tab、折叠面板)
条件渲染 Vue 3
<template>
  <!-- v-if: 条件为 false 时,DOM 直接不存在 -->
  <div v-if="status === 'running'">🟢 运行中</div>
  <div v-else-if="status === 'warning'">🟡 警告</div>
  <div v-else>🔴 停机</div>

  <!-- v-show: 只是隐藏,DOM 一直在 -->
  <div v-show="showDetail">详细信息面板</div>
</template>

<script setup>
const status = ref('running')   // 显示 🟢 运行中
const showDetail = ref(true)     // 显示详细信息
</script>
✅ 渲染结果

🟢 运行中

详细信息面板

3.6 v-for — 列表渲染

v-for = 循环渲染,相当于 Excel 的「往下填充」。最适合渲染列表数据。

🏭 工厂场景:设备状态列表

你有 5 台设备的状态数据(像 Excel 里 5 行),需要生成 5 个状态卡片。v-for 自动帮你循环生成。

列表渲染 — 设备状态看板 Vue 3
<template>
  <table>
    <tr v-for="machine in machines" :key="machine.id">
      <td>{{ machine.id }}</td>
      <td>{{ machine.name }}</td>
      <td>
        <span :class="machine.status">{{ machine.status }}</span>
      </td>
      <td>{{ machine.oee }}%</td>
    </tr>
  </table>
</template>

<script setup>
const machines = ref([
  { id: 1, name: 'CNC-A01', status: '运行中', oee: 87.5 },
  { id: 2, name: 'CNC-A02', status: '运行中', oee: 92.1 },
  { id: 3, name: 'CNC-B01', status: '停机',   oee: 0 },
  { id: 4, name: '注塑-C01', status: '警告',   oee: 65.3 },
])
</script>
✅ 渲染结果
编号设备名状态OEE
1CNC-A01运行中87.5%
2CNC-A02运行中92.1%
3CNC-B01停机0%
4注塑-C01警告65.3%
⚠️ v-for 必须加 :key

:key 类似数据库的主键,帮 Vue 高效追踪每个列表项。没有 key,列表更新时可能出现渲染错误。用唯一 ID(如设备编号),不要用 index。

模板语法速查表

指令作用简写Excel 类比
{{ }}显示数据=A1
v-bind绑定属性:单元格链接
v-on绑定事件@按钮 → 运行宏
v-model双向绑定输入框直连单元格
v-if条件渲染(销毁/创建)IF 条件显示行
v-show条件显示(显隐切换)隐藏行(行还在)
v-for循环渲染列表往下拖拽填充

04 · 组件化

组件 = 可复用的独立功能块。就像工厂里的标准化模块,拼装成完整产线。

🏭 工厂类比

看板大屏 = 一个大页面,上面有 10 个「设备卡片」。每个卡片就是一个组件。你写一次卡片组件,传不同数据就能生成 10 张卡片。

就像工厂的标准化工位:每个工位结构一样,只是加工的产品不同。你不需要为每个产品单独设计一条产线。

组件的数据流:Props 进,Emit 出

📊 Excel 类比
组件概念Excel 类比说明
Props函数的输入参数父组件传给子组件的数据(单向,只读)
Emit函数的返回值子组件通知父组件「发生了什么事」
组件自定义函数封装好的、可复用的功能块
子组件:OeeGauge.vue Vue 3
<!-- 一个 OEE 仪表盘卡片组件 -->
<template>
  <div class="oee-card">
    <h3>{{ title }}</h3>
    <!-- props 是父组件传进来的数据 -->
    <div class="gauge">{{ value }}%</div>
    <div class="bar" :style="{ width: value + '%' }"></div>
    <!-- 点击按钮,通知父组件 -->
    <button @click="handleClick">查看详情</button>
  </div>
</template>

<script setup>
// 1. Props = 输入参数(父组件传来的数据)
const props = defineProps({
  title: { type: String, required: true },
  value: { type: Number, default: 0 }
})

// 2. Emit = 输出事件(通知父组件)
const emit = defineEmits(['detail'])

const handleClick = () => {
  emit('detail', props.title)  // 把设备名传回给父组件
}
</script>
父组件:使用 OeeGauge Vue 3
<template>
  <!-- 像调用函数一样使用组件,:value 传入数据 -->
  <OeeGauge title="可用率" :value="92" @detail="onDetail" />
  <OeeGauge title="表现率" :value="88" @detail="onDetail" />
  <OeeGauge title="质量率" :value="95" @detail="onDetail" />
</template>

<script setup>
import OeeGauge from './OeeGauge.vue'

const onDetail = (name) => {
  console.log('查看详情:', name)
}
</script>
✅ 渲染结果

可用率

92%

表现率

88%

质量率

95%

组件通信方式总结

方式方向场景Excel 类比
Props父 → 子传递数据(设备名、OEE 值)函数入参
Emit子 → 父通知事件(点击、选择)函数返回值
Provide / Inject祖先 → 后代跨层级传数据(主题、全局配置)全局变量
Pinia(状态管理)任意组件全局共享数据(用户信息、设备列表)共享的工作表

05 · 组合式 API (Composition API)

Vue 3 的组合式 API 是目前推荐的写法。相比旧的 Options API,它更灵活、代码组织更好。

🏭 工厂类比

Options API = 按工种分组:所有焊接工在一个车间、所有装配工在另一个车间。简单但找人不方便。
Composition API = 按产线分组:每条产线有自己的焊接、装配、质检,一条龙。方便管理和复用。

Options API vs Composition API

Options API(Vue 2 风格) Vue 2
export default {
  data() {
    return { oee: 85 }
  },
  computed: {
    oeeLevel() { return this.oee >= 85 ? '优秀' : '需改善' }
  },
  methods: {
    refresh() { this.oee = 90 }
  },
  mounted() { this.refresh() }
}
Composition API + <script setup>(Vue 3 推荐 ✅) Vue 3
<script setup>
import { ref, computed, onMounted } from 'vue'

// 数据
const oee = ref(85)

// 计算属性
const oeeLevel = computed(() => oee.value >= 85 ? '优秀' : '需改善')

// 方法
const refresh = () => { oee.value = 90 }

// 生命周期
onMounted(() => refresh())
</script>

核心 API 一览

computed — 计算属性

像 Excel 公式:=IF(A1>=85, "优秀", "需改善")。依赖的数据变了,自动重算。

computed 示例 Vue 3
const oee = ref(87)
const quality = ref(95)

// computed = Excel 的公式,依赖变化自动重算
const totalOee = computed(() => {
  return ((oee.value * quality.value) / 100).toFixed(1)
})
// totalOee = 82.7(oee 或 quality 变了,自动更新)
✅ 结果

表现率: 87% × 质量率: 95% = 综合 OEE: 82.7%

watch — 侦听器

监视数据变化,触发副作用(调接口、打日志等)。像 Excel 的「数据变化时运行宏」。

watch 示例 Vue 3
import { ref, watch } from 'vue'

const oee = ref(85)

// 当 oee 变化时,触发回调
watch(oee, (newVal, oldVal) => {
  console.log(`OEE 从 ${oldVal} 变为 ${newVal}`)

  // 实际场景:OEE 低于阈值 → 发送告警
  if (newVal < 60) {
    sendAlert(`OEE 过低: ${newVal}%`)
  }
})

computed vs watch vs methods

computedwatchmethods
用途根据已有数据算出新值数据变化时执行副作用封装操作逻辑
缓存✅ 有缓存(依赖不变不重算)❌ 每次都执行❌ 每次都执行
返回值有(像公式)无(像宏)可有可无
Excel 类比=A1*B1VBA Change 事件自定义函数
场景格式化、过滤、计算调 API、发告警、打日志按钮点击、业务逻辑

06 · 生命周期

每个 Vue 组件从创建 → 挂载到页面 → 更新 → 销毁,经历一系列「生命阶段」。你可以在特定阶段插入自己的代码。

🏭 工厂类比

组件的生命周期 = 一台设备的开机关机流程

  • onMounted = 设备开机自检完成,开始采集数据
  • onUpdated = 设备参数调整后,重新校准
  • onUnmounted = 设备关机前,保存数据、断开连接

三大生命周期钩子

生命周期钩子 Vue 3
<script setup>
import { ref, onMounted, onUpdated, onUnmounted } from 'vue'

let timer = null
const oee = ref(0)

// ① onMounted:组件挂载后 → 开始获取数据
//    就像设备开机后,连上 MES 开始读数据
onMounted(() => {
  fetchOeeData()  // 首次加载 OEE 数据

  // 每 5 秒刷新一次(实时看板的核心!)
  timer = setInterval(() => {
    fetchOeeData()
  }, 5000)
})

// ② onUpdated:数据变化导致 DOM 更新后
onUpdated(() => {
  console.log('看板已更新,OEE:', oee.value)
})

// ③ onUnmounted:组件销毁前 → 清理定时器!
//    就像设备关机前要断开连接,否则会内存泄漏
onUnmounted(() => {
  clearInterval(timer)  // ⚠️ 必须清理!否则定时器永远在跑
  console.log('看板已关闭,定时器已清理')
})

const fetchOeeData = async () => {
  // 模拟从后端 API 获取数据
  oee.value = await getOeeFromApi()
}
</script>
⚠️ 实时看板最重要的:清理定时器!

onUnmounted 中必须 clearIntervalclearTimeout、取消 ECharts 实例。否则:

  • 定时器继续跑 → 无意义的网络请求 → 内存泄漏
  • 切换页面后,后台还在每 5 秒请求一次 API
  • ECharts 实例不销毁 → DOM 节点泄漏

生命周期速查

钩子时机常见用途工厂类比
onMounted组件挂载到页面后获取数据、启动定时器、初始化图表开机自检,开始采集
onUpdated数据变化→DOM 更新后操作更新后的 DOM参数调整后重新校准
onUnmounted组件销毁时清理定时器、取消订阅、销毁图表关机保存数据

07 · 实战:OEE 看板组件

综合前面的知识,我们来写一个完整的 OEE 看板卡片组件,使用 Vue 3 + ECharts。

OEE(Overall Equipment Effectiveness,设备综合效率)= 可用率 × 表现率 × 质量率。

OeeDashboard.vue — 完整组件代码 Vue 3 + ECharts
<template>
  <div class="oee-dashboard">
    <h2>{{ machineName }} — OEE 看板</h2>

    <!-- 三个指标卡片 -->
    <div class="metrics">
      <MetricCard title="可用率" :value="availability" color="#7ee787" />
      <MetricCard title="表现率" :value="performance" color="#89dceb" />
      <MetricCard title="质量率" :value="quality" color="#d2a8ff" />
    </div>

    <!-- 综合得分 -->
    <div class="total-oee">
      <h3>综合 OEE: {{ totalOee }}%</h3>
      <span :class="oeeLevel === '优秀' ? 'green' : 'yellow'">
        {{ oeeLevel }}
      </span>
    </div>

    <!-- ECharts 仪表盘图表 -->
    <div ref="chartRef" class="chart" style="width: 100%; height: 300px;"></div>

    <!-- 手动刷新按钮 -->
    <button @click="refreshData">刷新数据</button>
  </div>
</template>

<script setup>
import { ref, computed, watch, onMounted, onUnmounted } from 'vue'
import * as echarts from 'echarts'

// ============ Props ============
const props = defineProps({
  machineName: { type: String, default: 'CNC-A01' }
})

// ============ 响应式数据 ============
const availability = ref(92)    // 可用率
const performance = ref(88)     // 表现率
const quality = ref(95)          // 质量率
const chartRef = ref(null)       // DOM 引用
let chartInstance = null
let timer = null

// ============ computed 计算属性 ============
const totalOee = computed(() => {
  return ((availability.value * performance.value * quality.value) / 10000).toFixed(1)
})

const oeeLevel = computed(() => {
  return totalOee.value >= 85 ? '优秀' : '需改善'
})

// ============ watch 侦听器 ============
// 数据变化 → 自动更新 ECharts 图表
watch(totalOee, () => {
  updateChart()
})

// ============ 方法 ============
const initChart = () => {
  chartInstance = echarts.init(chartRef.value)
  updateChart()
}

const updateChart = () => {
  if (!chartInstance) return
  chartInstance.setOption({
    series: [{
      type: 'gauge',
      data: [{ value: totalOee.value, name: 'OEE' }],
      detail: { formatter: '{value}%' }
    }]
  })
}

const refreshData = async () => {
  // 从后端 API 获取最新数据
  const data = await fetch(`/api/oee/${props.machineName}`)
  availability.value = data.availability
  performance.value = data.performance
  quality.value = data.quality
  // 数据变了 → computed 自动更新 → watch 自动更新图表 ✅
}

// ============ 生命周期 ============
onMounted(() => {
  initChart()
  refreshData()
  // 每 10 秒自动刷新(实时看板)
  timer = setInterval(refreshData, 10000)
})

onUnmounted(() => {
  clearInterval(timer)           // 清理定时器
  chartInstance.dispose()         // 销毁 ECharts 实例
})
</script>
✅ 实际效果预览

CNC-A01 — OEE 看板

92%
可用率 Availability
88%
表现率 Performance
95%
质量率 Quality
综合 OEE: 76.9% 需改善
💡 代码中用到的知识点回顾
  • ref:三个响应式指标(availability, performance, quality)
  • computed:totalOee(自动计算)、oeeLevel(自动判断等级)
  • watch:totalOee 变化 → 自动更新 ECharts 图表
  • onMounted:初始化图表 + 首次加载数据 + 启动定时刷新
  • onUnmounted:清理定时器 + 销毁 ECharts 实例
  • props:接收设备名称参数

08 · Vue vs React 速查

岗位要求「至少熟悉 Vue 或 React 其中一个」。如果你学完 Vue 后想了解 React,这里是最核心的概念对照表。

🏭 一句话区别

Vue = 自动手动挡(自动帮你处理 DOM 更新,模板语法更直觉)
React = 纯手动挡(JSX 全靠函数调用,更灵活但代码量稍多)
两者都能到达同一个目的地(构建 Web 应用),只是开车方式不同。

概念 Vue 3 React
创建组件 <script setup> + <template> function Comp() { return JSX }
响应式数据 ref(0) / reactive({}) useState(0)
计算属性 computed(() => ...) useMemo(() => ..., [deps])
侦听变化 watch(val, fn) useEffect(() => {}, [deps])
生命周期 onMounted / onUnmounted useEffect(() => {}, [])
条件渲染 v-if="flag" {flag && <Comp />}
列表渲染 v-for="item in list" :key="item.id" {list.map(item => <Comp key={item.id} />)}
事件绑定 @click="handleClick" onClick={handleClick}
双向绑定 v-model="value" value + onChange(手动实现)
父传子 defineProps 函数参数 props
子传父 defineEmits 回调函数 props.onXxx
模板语法 HTML + 指令(v-if, v-for JSX(HTML 写在 JS 里)
状态管理 Pinia Redux / Zustand
路由 Vue Router React Router
开箱体验 更多内置功能(指令、过渡动画) 更轻量,功能靠生态补充
同一个功能:Vue vs React 对比
// ============ Vue 3 ============
<template>
  <input v-model="name" />
  <p v-if="name">你好, {{ name }}!</p>
</template>
<script setup>
import { ref } from 'vue'
const name = ref('')
</script>

// ============ React ============
import { useState } from 'react'

function App() {
  const [name, setName] = useState('')
  return (
    <>
      <input value={name} onChange={e => setName(e.target.value)} />
      {name && <p>你好, {name}!</p>}
    </>
  )
}

09 · 面试考点 — Top 10

以下为 Vue 高频面试题,每题附简明答案 + 一句话记忆法

1v-if 和 v-show 的区别?

v-if:条件为 false 时,DOM 元素不存在(真正的销毁/创建)。切换开销大,适合不频繁切换的场景(弹窗、权限控制)。

v-show:元素始终存在,只是 CSS display: none 切换。初始渲染开销大,但切换快,适合频繁切换(Tab 标签、折叠面板)。

一句话:v-if = 拔电源(彻底关机),v-show = 盖遮布(还在,只是看不见)。

2ref 和 reactive 的区别?

ref:可以包裹任意类型(数字、字符串、布尔、对象)。JS 中通过 .value 访问,模板中自动解包。支持整个替换。

reactive:只能包裹对象/数组。直接访问属性,不需要 .value。但不能整个替换对象(会丢失响应性)。

一句话:ref 万能但要多写 .value,reactive 好用但只能包对象。

推荐:优先用 ref,对象特别复杂时用 reactive

3computed 和 watch 和 methods 的区别?

computed:计算属性,依赖数据变了自动重算,有缓存。必须有返回值。像 Excel 公式。

watch:侦听器,监听某个数据变化后执行副作用(调 API、打日志、发告警)。不返回值。

methods:普通方法,每次调用都执行。用于事件处理、业务逻辑。

一句话:computed 算值、watch 做事、methods 随叫随到。

4v-for 中 key 的作用是什么?

key 帮 Vue 识别每个列表节点的身份,高效复用和重新排序现有元素。

没有 key 时,Vue 使用「就地复用」策略,可能导致列表更新时出现渲染错误(状态错位、动画异常)。

类比:key = 数据库主键。没有主键,更新时可能改错行。

最佳实践:用唯一的业务 ID(如设备编号),不要用 index(列表增删时 index 会变)。

5Vue 组件之间有哪些通信方式?
方式方向适用场景
Props父 → 子传递数据(最常用)
Emit子 → 父子组件通知父组件
Provide / Inject祖先 → 后代跨多层传数据(主题、配置)
Pinia任意组件全局状态管理
EventBus任意组件Vue 3 推荐用 mitt 库

一句话:Props 向下传,Emit 向上通知,Provide 跨层级,Pinia 全局共享。

6keep-alive 的作用?

keep-alive 包裹动态组件时,会缓存组件实例而不是销毁它们。

切换回来时,组件状态(表单输入、滚动位置等)还在,不用重新创建和请求数据。

类比:keep-alive = 待机而不是关机。切走时「待机」,切回来「唤醒」,状态全在。

场景:Tab 切换、列表页 → 详情页 → 返回列表页(保留搜索条件和滚动位置)。

7nextTick 是什么?什么时候用?

Vue 更新 DOM 是异步的。改了数据,DOM 不会立刻变,而是在下一个「tick」统一更新。

nextTick = 等 DOM 更新完成后执行回调。

使用场景

  • 改了数据后需要操作更新后的 DOM(获取高度、聚焦输入框)
  • v-if 条件变为 true 后操作新出现的元素

一句话:nextTick = 「等 DOM 更新完再做下一步」。

8Vue 2 和 Vue 3 有哪些主要区别?
特性Vue 2Vue 3
API 风格Options APIComposition API(推荐)
响应式原理Object.definePropertyProxy(更强大)
根实例new Vue()createApp()
多根节点❌ 不支持✅ 支持(Fragment)
Teleport❌ 无✅ 传送组件到任意 DOM
Suspense❌ 无✅ 异步组件加载状态
TypeScript支持较弱原生支持
性能基准更快(虚拟 DOM 重写)
9Vue 的响应式原理是什么?

Vue 3 使用 Proxy 实现响应式:

  1. 当你用 ref()reactive() 创建数据时,Vue 用 Proxy 包裹它
  2. 组件渲染时「读取」数据 → Proxy 记录「谁在用这个数据」(依赖收集)
  3. 当你「修改」数据 → Proxy 检测到变化 → 通知所有依赖它的组件更新

类比:就像 MES 系统监控设备状态 — 有人订阅了某设备的状态,当状态变化时,MES 自动通知所有订阅者。

10什么是虚拟 DOM?为什么需要它?

虚拟 DOM (Virtual DOM) = 用 JavaScript 对象来描述真实 DOM 结构的轻量副本。

  1. 数据变化 → 生成新的虚拟 DOM 树
  2. 对比新旧虚拟 DOM(Diff 算法)→ 找出差异
  3. 只把差异部分更新到真实 DOM(最小化 DOM 操作)

类比:就像工厂的变更单 — 不是每次都重建整条产线,而是只改需要改的工位。效率高很多。

为什么需要:直接操作真实 DOM 很慢(重排重绘),虚拟 DOM 通过批量+最小更新来提升性能。