梗概:
- 底层使用js原生的Proxy对象来拦截变量的访问与赋值
- 当在某个函数引用了响应式变量时, Vue将会执行track过程, 将该函数记录起来
- 当响应式变量更新的时候, Vue将会执行trigger过程, 实现响应式
- 比较复杂的对象中的属性也是支持响应式的trigger的
实例
组件模板中引用响应式变量
child::
组件模板中调用响应式变量
指向原始笔记的链接
- 组件模板根据Vue 模板渲染原理生成的Vue 渲染函数就是一个副作用,会被track所记录
- 当响应式变量更改时,会被Proxy 代理对象拦截,执行Proxy实例的 set回调函数(即trigger),把对应的所有副作用(即Vue 渲染函数)都重新执行一遍
- 得到渲染出来的vnode之后,与其他vnode一起构成虚拟DOM
- child::渲染VDOM
Map对象的响应式
<template>
<div v-for="(map, index) of mapList">
{{ index }} : {{ map.get(`test${index}`) }}
</div>
<button @click="mapList[1].set('test1', 'v2')"></button>
</template>
<script setup>
import { ref } from "vue";
let mapList = ref([]);
for (let i = 0; i < 3; i++) {
mapList.value.push(new Map([["test" + i, "v" + i]]));
}
</script>
<style scoped></style>
- 能够监听map对象的值的变化
类与闭包的响应式
<template>
<div>count: {{ obj.count }}</div>
<button @click="obj.addCount()"></button>
<div>packCount: {{ pack.getPackCount() }}</div>
<button @click="console.log(pack.addPackCount())"></button>
</template>
<script setup>
import { ref } from "vue";
class MyObj {
count = 0;
addCount() {
this.count++;
}
packCount() {
let selfCount = 0;
return {
addPackCount() {
selfCount++;
return selfCount;
},
getPackCount() {
return selfCount;
},
};
}
}
let obj = ref(new MyObj());
let pack = obj.value.packCount();
</script>- 能够监听类中属性的变量
- 但是不能监听闭包中变量的变化
真实的响应式结构
<script setup lang="ts">
import reactive from "@/components/reactive.vue";
import { getCurrentInstance, onMounted, ref } from "vue";
let rea = ref();
function show() {
console.log("component ref:\n", rea.value);
console.log("component's count:\n", rea.value.count);
console.log("component's obj\n", rea.value.obj);
console.log("component's refObj\n", rea.value.refObj);
}
</script>
<template>
<reactive ref="rea"></reactive>
<button @click="show">show</button>
</template>
<style scoped></style>子组件:
<template></template>
<script setup lang="ts">
import { ref, reactive } from "vue";
let count = ref(0);
let obj = reactive({
message: "outside",
obj2: {
message: "inside",
},
});
let refObj = ref({
message: "outside",
obj2: {
message: "inside",
},
});
function say() {
count.value++;
obj.message = "inside";
obj.obj2.message = "outside";
}
defineExpose({ count, obj, say, refObj });
</script>
<style></style>