一、模板语法
- 模板语法: {{}}, computed ,watch
- 指令
- 条件渲染,列表渲染v-if v-for
二、组件
- 组件通信: 父子props,子父$emit,兄弟/跨层级 provide/inject, event bus,vuex/pinia
- 插槽:
- 生命周期
二、核心机制-响应式,双向绑定
核心思想是数据劫持+发布-订阅模式。
2.1 原理

2.1.1 Vue 2的响应式原理:基于 Object.defineProperty
Vue 2通过 Object.defineProperty
API来劫持数据的读取和设置(getter/setter)。
实现过程主要分为以下几个步骤:
-
数据劫持 (Observer)
- 当一个普通的JavaScript对象被传入Vue实例作为
data
选项时,Vue会遍历此对象的所有属性。 - 对于每个属性,Vue会使用
Object.defineProperty
重新定义它的get
和set
方法。 - 这样,当读取 (
get
) 这个属性时,Vue就知道"谁用了这个数据"。 - 当修改 (
set
) 这个属性时,Vue就能发出通知,告诉那些用到它的地方进行更新。
- 当一个普通的JavaScript对象被传入Vue实例作为
-
依赖收集 (Dep)
- 在
getter
中,Vue会进行依赖收集。 - 每个被劫持的属性都会拥有自己的一个依赖管理器 (Dep对象) 。
- 当视图在渲染 或计算属性 在计算时,会创建一个Watcher (订阅者)。这个Watcher在求值过程中会触发数据的
getter
。 - 此时,
Dep
就会把这个当前的Watcher
添加到自己的订阅者列表里。这就建立了"数据→依赖(Watcher)"的关系。
- 在
-
派发更新 (Notify)
- 当数据的值被修改,即触发了
setter
时,Vue会通知对应的Dep
。 Dep
会遍历它管理的所有Watcher
,并调用它们的update
方法。Watcher
的update
方法最终会触发组件的重新渲染(re-render
)或计算属性的重新计算,从而将最新的数据反映到视图上。
- 当数据的值被修改,即触发了
Vue 2实现的局限性:
- 无法检测对象属性的添加或删除 :由于
Object.defineProperty
是在初始化时遍历属性进行劫持的,所以后续新增的属性不是响应式的(需使用Vue.set
)。 - 对数组的限制 :无法劫持数组的索引操作(如
arr[index] = newValue
)和修改长度的操作(如arr.length = 0
)。Vue通过重写数组的7个变更方法(push
,pop
,shift
,unshift
,splice
,sort
,reverse
)来实现数组的响应式。
2.1.2 Vue 3的响应式原理:基于 Proxy
Vue 3使用了ES6的 Proxy
来重写了响应式系统,解决了Vue 2的大部分局限性。
实现过程:
-
数据劫持 (Reactive)
- Vue 3通过
reactive()
函数创建一个对象的响应式代理。 Proxy
可以拦截对一个对象任何性质 的操作,包括属性的读取 (get
)、设置 (set
)、删除 (deleteProperty
)、in
操作符等共13种,而不仅仅是get
和set
。- 这意味着,无论是已有属性还是新增、删除属性,都能被完美劫持。
- Vue 3通过
-
依赖收集与派发更新 (Track/Trigger)
track
(追踪) :在Proxy
的get
拦截中,Vue会执行track
函数,用于建立"目标对象→属性→依赖"的关系。这里的"依赖"在Vue 3中被称为effect
,类似于Vue 2的Watcher
。trigger
(触发) :在Proxy
的set
、deleteProperty
等拦截中,Vue会执行trigger
函数,它会根据操作的类型和key,找到所有相关的effect
并执行它们。
-
Ref
- 对于原始值(如
number
,string
),Proxy
无法代理。Vue 3提供了ref
函数来解决。 ref
会创建一个响应式的引用对象(RefImpl
实例),该对象的.value
属性才是真正的值。访问.value
时进行依赖收集,修改.value
时触发更新
- 对于原始值(如
一个组件一个渲染 Watcher,不是多个,Dep是多个。 Watcher(订阅者)订阅了 Dep(发布者)。 你修改数据 -> 数据的 Dep (发布者) 发出通知 -> 所有订阅了该Dep的 Watcher (订阅者) 收到通知 -> Watcher 执行更新操作 -> 视图变化

kotlin
// 伪代码,在 userInfo.age 的 getter 内部
if (Dep.target) { // Dep.target 就是当前正在执行的 Watcher (渲染 Watcher)
dep.depend(); // 核心:让 Dep 收集这个 Watcher
}
return value;
scss
// 伪代码,在 userInfo.age 的 setter 内部
set(newVal) {
value = newVal;
dep.notify(); // 核心:Dep 通知所有订阅者!
}
2.2 虚拟DOM
在 Vue 2 中,响应式系统和虚拟 DOM 是两个独立但协同工作的核心模块,两者共同支撑了 Vue 的数据驱动视图能力。
- 响应式系统:负责追踪数据变化,当数据更新时通知相关依赖(组件)。
- 虚拟 DOM:负责将数据变化高效地映射到真实 DOM,是响应式系统触发更新后的 "渲染执行者"。
2.3 模板编译
- 阶段 1:解析(Parse)------ 模板 → AST
- 阶段 2 转换(Transform)------ AST → 优化后的 AST
-
指令转换:
- 将
v-if
转换为条件判断逻辑(if/else
)。 - 将
v-for
转换为循环逻辑(Array.map
)。 - 将
v-bind
、v-on
转换为对应的属性绑定和事件监听(如onClick
)。 - 将
{{ name }}
插值转换为_ctx.name
(访问组件上下文的变量)。
- 将
- 阶段 3 生成(Generate)------ AST → 渲染函数

三、核心机制-组合式api
Vue 组合式 API 的原理是一个有机结合体:
- 以响应式系统为引擎 :
ref
和reactive
提供了数据驱动的动力。 - 以
setup()
函数为入口和上下文:它创建了组件初始化的执行环境,并收集所有暴露出的状态和方法。 - 以生命周期钩子函数为连接器:它们将逻辑与组件的生命周期阶段挂钩。
- 以普通 JavaScript 函数为复用载体:通过函数和闭包,将响应式状态和逻辑封装成可复用的单元。
它并没有引入全新的魔法,而是更底层、更灵活地暴露了 Vue 响应式系统的能力,让开发者能够像编写普通 JavaScript 代码一样来组织组件逻辑,从而获得了更好的类型推断、逻辑复用和代码组织能力。
- 当渲染函数读取到
setup
返回的某个响应式属性(如count.value
)时,就会触发该响应式属性的getter
,从而将这个组件的渲染 effect (可以看作是一个特殊的 Watcher)收集为依赖。这就建立了数据 → 视图的依赖关系。
- 虚拟Dom
四、高级特性 vue 2 mixin
Vue 中的 mixin
是一种代码复用机制,用于将多个组件中可复用的逻辑(如数据、方法、生命周期钩子等)提取到一个独立的对象中,然后在多个组件中 "混入" 这些逻辑,实现代码共享。
-
合并规则:
- 数据(
data
):组件自身数据优先级高于mixin
,若存在同名属性,组件数据会覆盖mixin
。 - 方法、计算属性:同名时,组件自身的会覆盖
mixin
的。 - 生命周期钩子:
mixin
中的钩子会比组件自身的同名钩子先执行(如mixin
的created
先于组件的created
执行)。 - 组件选项(如
components
、directives
):会合并为一个对象,同名键会被组件自身覆盖。
- 数据(
-
缺点:
-
命名冲突风险:
mixin
与组件、mixin
之间可能出现同名属性 / 方法,不易排查。 -
逻辑来源模糊:组件中使用的属性或方法可能来自多个
mixin
,调试时难以追溯。 -
灵活性有限:无法向
mixin
传递参数,难以实现个性化逻辑。
Vue 3 中推荐使用 组合式 API(
setup
函数 + 自定义 Hooks) 替代mixin
,通过函数调用的方式复用逻辑,解决了mixin
的命名冲突和来源模糊问题,更适合复杂场景。 -
五、keep alive
-
缓存机制
<keep-alive>
会将包裹的组件实例缓存到一个内部对象(通常称为cache
)中,键值一般是组件的name
或标签名。当组件需要被切换(如使用<router-view>
或v-if
)时,不会执行beforeDestroy
和destroyed
生命周期,而是被缓存起来。 -
激活与失活
- 被缓存的组件再次渲染时,不会执行
created
、mounted
等初始化生命周期,而是触发activated
钩子。 - 组件被缓存隐藏时,不会销毁,而是触发
deactivated
钩子。
- 被缓存的组件再次渲染时,不会执行
-
DOM处理
<keep-alive>
自身不会渲染 DOM 节点,也不会出现在组件的父链中。它会将缓存的组件实例保存在内存中,对应的 DOM 节点会被暂时移除或隐藏,重新激活时再插入到文档中。activated
是 Vue 的特殊生命周期钩子 ,需要与<keep-alive>
配合使用
为什么不会重新渲染?
Vue 的组件生命周期在首次加载 Tab2
时会正常执行:created
-> mounted
-> ...。
当你切换到 Tab1
时,Tab2
会执行 deactivated
。
当你再次切换回 Tab2
时,Vue 会直接从缓存中恢复它的整个实例(包括所有的数据、DOM状态),因此只会触发 activated
钩子,而不会再次触发 created
和 mounted
。
六、路由管理
vue-router
七、状态管理Pinia/Vuex

组件 -> Dispatch Action -> Commit Mutation -> Modify State
组件 -> Call Action -> Directly Modify State
或 组件 -> Directly Modify State
其他、React Vue对比
react vue 有哪些功能是对方没有的?
- React 并发渲染 可中断 useTransition
- vue 双向绑定、类html模板语法指令系统