Vue 3 的 Ref 是一个集合,包括多个与响应式引用相关的功能,这些功能共同构成了 Vue 3 响应式系统的重要组成部分。以下是更全面的介绍:
1.ref
ref
接受一个内部值并返回一个响应式且可变的 ref 对象。这个对象具有一个 .value
属性,用于读取和设置其内部值。通过 ref
,我们可以将基本数据类型或对象转换为响应式引用,并在组件中方便地跟踪和更新这些值。
<template>
<div>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
// 使用 ref 创建一个响应式引用,并为其指定初始值和类型
const count = ref<number>(0);
// 定义一个方法来增加计数器的值
const increment = () => {
count.value++;
};
</script>
2.shallowRef
shallowRef
与 ref
类似,但它只对其引用的根级别属性进行响应式转换。如果引用的值是一个对象或数组,那么该对象的内部属性或数组的元素不会变为响应式。这使得 shallowRef
在处理大型数据结构时更为高效,因为它避免了不必要的深度响应式转换。
<template>
<div>
<p>Nested Object: {{ nestedObject.value.prop1 }}</p>
<button @click="updateNestedObject">Update Nested Object</button>
</div>
</template>
<script setup lang="ts">
import { shallowRef } from 'vue';
// 创建一个浅响应式的对象引用
const nestedObject = shallowRef({
prop1: 'Initial Value',
prop2: 'Another Value',
});
// 定义一个方法来更新嵌套对象的属性
const updateNestedObject = () => {
nestedObject.value.prop1 = 'Updated Value';
};
</script>
如果
nestedObject
的直接属性(如prop1
和prop2
)发生变化,Vue 将能够检测到这些变化并更新 DOM。如果
nestedObject
的属性本身包含复杂的嵌套结构(如数组或对象),则这些内部结构的变化不会触发响应式更新。
3.toRef 和 toRefs
toRef
和 toRefs
是用于处理响应式对象的工具。toRef
基于响应式对象上的一个属性,创建一个对应的 ref,这样创建的 ref 与其源属性保持同步。而 toRefs
则将响应式对象的属性转换为独立的响应式引用,使得在模板中可以直接使用这些属性,而无需通过 .value
访问。
<template>
<div>
<p>Name: {{ name }}</p>
<p>Age: {{ age }}</p>
<button @click="incrementAge">Increment Age</button>
</div>
</template>
<script setup lang="ts">
import { reactive, toRef, toRefs } from 'vue';
// 创建一个响应式对象
const state = reactive({
name: 'John Doe',
age: 30,
});
// 使用 toRef 提取响应式引用
const nameRef = toRef(state, 'name');
// 使用 toRefs 解构出响应式引用对象
const { age } = toRefs(state);
// 定义一个方法来增加年龄
const incrementAge = () => {
age.value++;
};
</script>
4.customRef
customRef
允许你创建自定义的响应式引用。它接受一个工厂函数,该函数可以定义自己的依赖跟踪和触发更新的逻辑。这使得 customRef
在处理复杂逻辑或需要更精细控制响应式行为时非常有用。
<template>
<div>
<p>Custom Ref Value: {{ customValue }}</p>
<button @click="incrementCustomValue">Increment Custom Value</button>
</div>
</template>
<script setup lang="ts">
import { customRef } from 'vue';
// 自定义 ref 的 getter 和 setter
function customRefFactory<T>(defaultValue: T) {
let value = defaultValue;
return customRef<T>((track, trigger) => {
return {
get() {
track();
return value;
},
set(newValue: T) {
value = newValue;
trigger();
},
};
};
}
// 使用自定义 ref 工厂函数创建响应式引用
const customValue = customRefFactory(0);
// 定义一个方法来增加自定义值的值
const incrementCustomValue = () => {
customValue.value++;
};
</script>
5.unref
unref
是一个辅助函数,用于处理可能是 ref 的值。如果传递给 unref
的值是一个 ref,则返回其 .value
;否则,直接返回该值。这在你不确定一个值是否是 ref 时特别有用,可以避免在模板或计算属性中不必要的 .value
访问。
<template>
<div>
<p>Value from ref: {{ refValue }}</p>
<p>Value from non-ref: {{ nonRefValue }}</p>
</div>
</template>
<script setup lang="ts">
import { ref, unref } from 'vue';
// 创建一个 ref
const refValue = ref('This is from a ref');
// 创建一个非 ref 的值
const nonRefValue = 'This is not from a ref';
// 一个函数,它接受一个可能是 ref 的值,并使用 unref 来获取其值
function displayValue(possibleRef: any) {
const value = unref(possibleRef);
alert(`The value is: ${value}`);
}
// 在模板被挂载后调用 displayValue 函数,分别传入 ref 和非 ref 的值
onMounted(() => {
displayValue(refValue); // 显示 'This is from a ref'
displayValue(nonRefValue); // 显示 'This is not from a ref'
});
</script>
6.isRef
isRef
是一个用于检查一个值是否为 ref 的函数。它返回一个布尔值,指示给定的值是否是一个 ref 对象。这在编写可重用逻辑或工具函数时非常有用,因为你可以根据值是否为 ref 来采取不同的操作。
<template>
<div>
<p v-if="isCountRef">Count is a ref: {{ count }}</p>
<p v-else>Count is not a ref: {{ count }}</p>
<button @click="increment">Increment</button>
</div>
</template>
<script setup lang="ts">
import { ref, isRef } from 'vue';
const count = ref(0);
const isCountRef = isRef(count);
const increment = () => {
count.value++;
}
</script>