🌈个人主页:前端青山
🔥系列专栏:Vue篇
🔖人终将被年少不可得之物困其一生
依旧青山,本期给大家带来vue篇专栏内容:vue3-响应式函数
目录
ref 响应式函数
引言:
ref 函数
reactive 函数
Reactive 与 ref 对比
vue3响应式原理
1、vue3响应式原理
ref 响应式函数
引言:
如下代码:当点击执行changeFn函数,修改setup中定义的变量时,发现页面中的name和age的数据并没有修改,说明该数据不是响应式数据
<template>
<div>111</div>
<p>{{ name }}--{{ age }}</p>
<button @click="changeFn">changeFn</button>
</template>
<script>
export default {
name: "App",
setup() {
//定义变量
let name = "张三";
let age = 20;
// 定义方法
function changeFn() {
name = "李四";
age = 30;
}
return {
//setup函数返回值为一个对象
name,
age,
changeFn,
};
},
};
</script>
ref 函数
-
它是 vue3中的一个函数,一般用于将基本类型数据处理成响应式数据。
-
作用:定义一个基本类型的响应式的数据,只有数据成为响应式数据,这样当数据变化时,才能被监测到。
-
使用时需要从vue中引入
-
语法:const xxx =ref(数据变量);结果 返回一个 RefImpl 的引用对象,获取时为 xxx.value
-
在页面模板中使用数据直接 使用插值表达式,不需要加value <p>姓名:{{ name }}</p>,因为vue3会自动帮你.value,所以可以拿到值
-
ref 函数实现数据响应式的原理还是利用了vue2的Object.defineProperty() 给数据设置 get set 监听函数,如下图:
-
接收的数据类型可以是基本类型(实现响应式原理为Object.defineProperty()),也可以是对象类型(当为对象时,实现响应式的原理就是Proxy不是Object.defineProperty())
点击如下change事件,修改name 和age
<template>
<div>
<!--name这个ref 引用对象在使用时不需要加value,vue3会自动帮你加value,所以可以拿到值-->
<p>{{ name }}--{{ age }}</p>
<p>{{ job.type }}--{{job.salary}}</p>
<p @click="change">说话</p>
</div>
</template>
<script>
import { ref } from "vue"; // 引入响应式函数ref
export default {
name: "App",
setup() {
let name = ref("张三"); //返回一个 ref 引用对象
let age = ref(20);
console.log(name)
// 当ref传的参数为对象时
let job = ref({
type: "前端工程师",
salary: "20k",
});
function change() {
name.value = "李四"; // ref对象.value 修改其值
age.value = 30;
job.value.type = "后端开发工程师";
job.value.salary = "30k";
}
return {
name,
age,
change,
job
};
},
};
</script>
reactive 函数
1.定义一个对象类型的响应式数据,返回一个Proxy 实例对象,不能用于基本数据类型,否则报错。(基本类型响应式数据使用ref)。
语法:const 代理对象= reactive(源对象) ,接收一个对象或数组,返回一个代理对象(即Proxy源对象)
-
使用时先从vue中引入
<script>
import { reactive } from "vue";
...
</script>
-
代码如下:
<template>
<p>{{ job.type }} --{{ job.salary }}--{{ job.like.a.b }}--{{job.content}}</p>
<p v-for="(item, index) in foodArr" :key="index">{{ item }}</p>
<button @click="changeFn">changeFn</button>
</template>
<script>
import { reactive } from "vue";
export default {
name: "App",
components: {},
setup() {
//定义对象
let job = reactive({
type: "前端工程师",
salary: "20k",
like:{
a:{
b:'不告诉你'
}
}
});
console.log(job);
//定义数组
let foodArr = reactive(["刷抖音", "敲代码"]);
console.log(foodArr);
// 定义方法
function changeFn() {
job.type = "后端开发工程师";
job.salary = "30k";
job.content = "写代码"; // 给对象添加属性
foodArr[0]='买包包' // 通过下标修改数组
}
return {
//setup函数返回值为一个对象
job,
changeFn,
foodArr
};
},
};
</script>
-
vue3中使用proxy 实现的数据响应去掉了vue2中不能检测到对象添加属性和通过下标修改数组而无法检测的情况。
Reactive 与 ref 对比
1、数据定义角度对比:
-
ref用来定义:基本数据类型
-
reactive 用来定义: 对象或数组类型数据
注意:ref也可以定义对象或数组类型数据,它内部还是通过reactive转换成代理对象
2、原理角度对比:
-
ref通过Object.defineProperty() 的get和set 实现数据的响应式 即(数据劫持)
-
reactive 通过Proxy 实现数据响应式的,并通过Reflect 来操作源对象数据的。
3、从使用角度对比:
-
ref 定义的数据操作时需要使用 .value, 而插值表达式中使用时,不需要使用 .value
-
reactive 定义的数据操作都不需要 .value
vue3响应式原理
-
对象数据新增属性和删除属性,不存在vue2.x 中的问题了。
<template>
<div>
<p>{{ person.name }}</p>
<p>{{ person.age }}</p>
<p>{{ person.sex }}</p>
<button @click="addSex">添加属性</button>
<button @click="deleteSex">删除属性</button>
</div>
</template>
<script>
import { reactive } from "vue";
export default {
name: "App",
components: {},
setup() {
let person = reactive({
name: "张三",
age: 20,
});
console.log(person);
//定义添加属性
function addSex() {
person.sex = "男";
console.log(person);
}
// 定义删除属性
function deleteSex() {
delete person.sex;
console.log(person);
}
return {
person,
addSex,
deleteSex,
};
},
};
</script>
-
数组数据直接通过修改下标,修改数组,不存在vue2.x 中的问题了。
<template>
<div>
<p v-for="(item, index) in person.like" :key="index">{{ item }}</p>
<button @click="change">修改数组的值</button>
</div>
</template>
<script>
import { reactive } from "vue";
export default {
name: "App",
components: {},
setup() {
let person = reactive({
name: "张三",
age: 20,
like: ["打球", "敲代码"],
});
console.log(person); // proxy 实例对象
function change() {
person.like[0] = "打台球";
}
return {
person,
change,
};
},
};
</script>
1、vue3响应式原理
首先说一下Reflect的作用。
// Reflect是window下的一个内置对象
// 1. 使用reflect 访问数据
let obj = {
name: '张三',
age: 20
}
console.log(Reflect.get(obj, 'name')); // 张三
// 2.使用Reflect 修改数据
Reflect.set(obj, 'age', 50)
console.log(obj);
//3.使用Reflect删除数据
Reflect.deleteProperty(obj, 'name')
console.log(obj);
vue3响应原理代码:
通过Proxy代理,拦截对象中任意属性的变化,包括属性的读取,修改、设置、删除。
通过Reflect 反射对被代理对象的属性进行操作。
let data = {
name: "张三",
age: 30
}
console.log(Proxy);
// 使用p 对象代理data, Proxy为window 下的内置代理函数
let p = new Proxy(data, {
// 读取属性
get(target, propName) {
// target 就是 data
console.log(`读取p上个${propName}属性`);
return Reflect.get(target, propName)
},
// 修改和设置属性
set(target, propName, value) {
// value 为赋的值
console.log(`修改p的${propName}属性`);
// target[propName] = value
Reflect.set(target, propName, value)
},
//删除属性
deleteProperty(target, propName) {
console.log(`删除p上的${propName}属性`);
// return delete target[propName]
return Reflect.deleteProperty(target, propName)
}
})