工作了将近10的前端,计划用30天的时间,系统整理vue知识点,DAY 1 的响应式开始。静下心来相信一定有所收获
下面是vue2 与 vue3 手写计数器
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue2 vs Vue3 计数器 · 响应式对比</title>
</head>
<!-- // 引入vue2和vue3的cdn -->
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<body>
<h1>vue 2 的 计数器</h1>
<div id="app">
<p>{{ count }}</p>
<button @click="count++">增加</button>
<button @click="count--">减少</button>
<button @click="count = 0">重置</button>
</div>
<script>
new Vue({
el: '#app',
data() { // 问题1:为什么是一个函数呢
return {
count: 0
}
}
})
</script>
<h1>vue 3 的 计数器</h1>
<div id="app2">
<p>{{ count }}</p>
<button @click="count++">增加</button>
<button @click="count--">减少</button>
<button @click="count = 0">重置</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@3"></script>
<script>
const { createApp, ref } = Vue; // 问题2:这里是引用的是 ref 那么复杂类型呢
setup() {
const count = ref(0);
return { count };
}
}).mount('#app2');
</script>
问题3 : vue2 和 vue3 一个是 option API 一个是compsistion API ,核心的问题响应式为何修改呢
</body>
</html>
上述代码很直观的反馈出来Vue2 与 Vue2 的区别 下面将围绕以下三个问题进行刨析:
- Vue2的
data为什么必须是一个函数? - Vue3的
ref和reactive有什么区别?各自适合什么场景? - 为什么Vue3要改用Proxy替代Vue2的
Object.defineProperty?
Vue2 Data 为什么是一个函数 及其 属性避坑
解析 vue2 实例种data 可以是个对象,但是组件中的就必须是函数
核心原因:数据隔离
-
对象形式 :JavaScript 中的对象是引用类型。如果
data是对象,所有组件实例将共享同一个内存地址。修改实例 A 的数据,实例 B 也会跟着变。 -
函数形式 :当
data是一个函数时,每次创建新实例,Vue 都会调用该函数,返回一个全新的数据对象拷贝。这保证了每个组件实例数据的独立性。 -
总结: 原因很简单,就是对象如果
key值一样会被覆盖,但是函数一直是唯一的扩展:
-
vue2 的执行顺序:
Props → Methods → Data → Computed → Watch
-
vue2 的生命周期 :
创建阶段 → 挂载阶段 → 更新阶段 → 销毁阶段 beforeCreated → Created → beforeMount → Mounted → beforeUpdate → updated → beforeDestroy → destroyed
其中这个
activated和deactivated是当keep-alive 触发
为什么Vue3要改用Proxy替代Vue2的Object.defineProperty?
在还没有出现Proxy 时候,JS 只能用 Object.definedProperty 来监听属性
弊端:
- ❌ 无法监听新增属性
- ❌ 无法监听数组下标
- ❌ 必须提前知道属性名,无法动态拦截所有操作
Proxy 出现
Proxy 是 ES6(2015)引入的一个强大特性,它的中文意思是"代理"。
你可以用它来为一个对象创建一个代理,所有对原对象的操作(读、写、删除、遍历等)都会先经过这个代理。
js
const proxy = new Proxy(target, handler);
- target 是代理的对象
- handler 一个对象,定义拦截处理函数
- 返回的代理对象,你应该使用它代替原对象 handler 中 函数
- get(target, key)
- set(target,key,vaue)
- has(target,key)
- deleteProperty(target,key)
- ownKeys(target)
- apply(target, thisArg, args)
- construct 使new
Vue3的ref和reactive有什么区别?各自适合什么场景?
- Ref 的使用 作用: Ref 是一个普通的JavaScript 变量(可以是基本的数据类型,也可以是引用类型) 包装成的响应式的数据
官网文档的解释: 接受一个内布值,返回一个响应式的,可以更改的ref对象,此对象只有一个指向其内部的属性.value
参数
ref 的参数可以是: 基本数据类型、引用数据类型、DOM的ref属性值
基本用法
首先先看看ref 函数传入的参数为 原始数据类型的情况
原始数据类型有7个,分别:String/Bumber/Boolean/BigInt/Symbol/Null/Undefined
- reactive 的 使用
作用:
与将内部值包装在特殊对象中的 ref 不同,reactive() 将使对象本身具有响应性
响应式对象是 JavaScript 代理,其行为就和普通对象一样。不同的是,Vue 能够拦截对响应式对象所有属性的访问和修改,以便进行依赖追踪和触发更新。
对比二者的区别 以及使用场景
优先用ref的场景
- 基本类型数据(字符串、布尔值等)。
- 需跨组件传递的独立值(
props传递ref更安全)。 - 需要整体替换的对象(如从API拉取全新配置)。
优先用reactive的场景
- 关联属性组(如表单的
{name, email, submitted})。 - 深度嵌套对象(如
user.orders[0].products)。 - 无需替换根引用的对象(如组件局部状态)。
建议
- 小项目用ref 减少心智负担
- 中大型项目: 基础类型用
ref关联对象用reactive混合的用toRefs解构造