目录
一、Vue3响应式基础
1.声明响应式状态
我们可以使用 reactive() 函数创建一个响应式对象或数组入过想要使用,可以在setup()
函数中定义并返回。
<script>
import { reactive } from "vue";
export default {
// `setup` 是一个专门用于组合式 API 的特殊钩子函数
setup() {
let oneNumber = reactive({ count: 0 });
function add() {
oneNumber.count++;
}
// 暴露 state 到模板
return {
oneNumber,
add,
};
},
};
</script>
<template>
<button @click="add">
{{ oneNumber.count }}
</button>
</template>
<style scoped></style>
在 setup()
函数中手动暴露大量的状态和方法非常繁琐,因此我们可以使用<script setup>来简化代码,如下:
<script setup>
import { reactive } from "vue";
let oneNumber = reactive({ count: 0 });
function add() {
oneNumber.count++;
}
</script>
<template>
<button @click="add">
{{ oneNumber.count }}
</button>
</template>
2.DOM 更新时机
当更改响应式状态后,DOM 会自动更新。然而DOM 的更新并不是同步的。相反,Vue 将缓冲它们直到更新周期的 “下个时机” 以确保无论你进行了多少次状态更改,每个组件都只更新一次。若要等待一个状态改变后的 DOM 更新完成,可以使用 这个全局 API
<script setup>
import { reactive, nextTick } from "vue";
let oneNumber = reactive({ count: 0 });
function add() {
oneNumber.count++;
console.log(document.getElementById("addBtn").textContent);
nextTick(() => {
// 访问更新后的 DOM
console.log(document.getElementById("addBtn").textContent);
});
}
</script>
<template>
<button @click="add" id="addBtn">
{{ oneNumber.count }}
</button>
</template>
显而易见的是,当执行add时,访问dom的内容是操作count之前的值,在nextTick之后才为count更新后的值
3.深层响应性和浅层响应性
深层响应性:
在 Vue 中,状态都是默认深层响应式的。这意味着即使在更改深层次的对象或数组,改动也能被检测到。
<script setup>
import { reactive } from "vue";
let oneNumberObj = reactive({
nested: { count: 0 },
arr: ["hello", "vue3"],
});
function add() {
oneNumberObj.nested.count++;
oneNumberObj.arr[0] = "ts" + oneNumberObj.nested.count;
}
</script>
<template>
<button @click="add" id="addBtn">
{{ oneNumberObj.nested.count }}--{{ oneNumberObj.arr[0] }}
</button>
</template>
显而易见的是,当执行add时,count和arr都可以做出相应
浅层响应性:
一个浅层响应式对象里只有根级别的属性是响应式的。
<script setup>
import { reactive,shallowReactive } from "vue";
let oneNumberObjShallow = shallowReactive({
nested: { count: 0 },
arr: ["hello", "vue3"],
});
function add() {
oneNumberObjShallow.nested.count++;
oneNumberObjShallow.arr[0] = "ts" + oneNumberObjShallow.nested.count;
}
</script>
<template>
<button @click="add" id="addBtn">
{{ oneNumberObjShallow.nested.count }}--{{ oneNumberObjShallow.arr[0] }}
</button>
</template>
显而易见的是,当执行add时,count和arr不可以做出相应
4.响应式代理 vs. 原始对象
reactive()
返回的是一个原始对象的 Proxy,它和原始对象是不相等的。
只有代理对象是响应式的,更改原始对象不会触发更新。因此,使用 Vue 的响应式系统的最佳实践是 仅使用你声明对象的代理版本
对同一个原始对象调用 reactive()
会总是返回同样的代理对象,而对一个已存在的代理对象调用 reactive()
会返回其本身
如下:
<script setup>
import { reactive } from "vue";
let oneNumber = { count: 0 };
let proxy = reactive(oneNumber)
function addProxy() {
proxy.count++;
console.log(proxy === oneNumber) //false
console.log(reactive(oneNumber) === proxy) //true
console.log(reactive(proxy) === proxy) //true
}
</script>
<template>
<button @click="addProxy">
{{ proxy.count }}
</button>
</template>
5.用 ref()
定义响应式变量
reactive()仅对对象类型有效,因此我们可以使用ref()
来允许我们创建可以使用任何值类型的响应式
ref()
将传入参数的值包装为一个带 .value
属性的 ref 对象
当 ref 在模板中作为顶层属性被访问时,它们会被自动“解包”,所以不需要使用 .value
跟响应式对象不同,当 ref 作为响应式数组或像 Map
这种原生集合类型的元素被访问时,不会进行解包。
如下:
<script setup>
import { ref,reactive } from 'vue'
const oneNumber = ref(0)
const oneStr = reactive([ref('Vue3')])
function add() {
oneNumber.value++
}
</script>
<template>
<button @click="add">
{{ oneNumber }} <!-- 无需 .value -->
</button>
<div>{{ oneStr[0].value }}</div>
</template>
有问题可以在下面评论,我会为大家解答。