# toRef
-
为源响应式对象上的某个属性创建一个 ref对象, 二者内部操作的是同一个数据值, 更新时二者是同步的
-
区别ref: 拷贝了一份新的数据值单独操作, 更新时相互不影响
-
应用: 当要将 某个prop 的 ref 传递给复合函数时,toRef 很有用
<template> <h3>state:{{ state }}</h3> <h3>age:{{ age }}</h3> <h3>money:{{ money }}</h3> <hr /> <button @click="update">更新数据</button> </template> <script lang="ts"> import { defineComponent, reactive, ref, toRef } from "vue"; export default defineComponent({ name: "App", setup() { const state = reactive({ age: 5, money: 100, }); const age = toRef(state, "age"); const money = ref(state.money); const update = () => { age.value += 10; money.value += 10; }; console.log(age); console.log(money); return { state, age, money, update }; }, }); </script>
-
案例:
<template> <h2>子组件</h2> <h3>age:{{age}}</h3> <h3>length:{{length}}</h3> </template> <script lang="ts"> import { computed, defineComponent, Ref, toRef } from "vue"; function useGetLength(age: Ref) { return computed(() => { // 将age属性转化成ref,与原属性是共通的 return age.value.toString().length }) } export default defineComponent({ name: "Child", props:["age"], setup(props) { console.log(props.age); const length = useGetLength(toRef(props,"age")) console.log(length); return { length } } }); </script>
<template> <h3>state:{{state}}</h3> <h3>age:{{age}}</h3> <h3>money:{{money}}</h3> <hr> <button @click="update">更新数据</button> <hr> <Child :age = "age"/> </template> <script lang="ts"> import { defineComponent, reactive, ref, toRef } from "vue"; import Child from "./components/Child.vue" export default defineComponent({ name: "App", components: { Child }, setup() { const state = reactive({ age: 5, money: 100 }) const age = toRef(state, "age") const money = ref(state.money) const update = () => { age.value+=10 } return { state, age, money, update }; }, }); </script>
# customRef
-
创建一个自定义的 ref,并对其依赖项跟踪和更新触发进行显式控制
-
需求: 使用 customRef 实现防抖的示例
<template> <h2>customRef</h2> <input type="text" v-model="keyword"> <p>{{keyword}}</p> </template> <script lang="ts"> import { customRef, defineComponent } from "vue"; // 自定义hook防抖 function useAntiShake<T>(value: T, delay = 200) { let timeOutId: number return customRef((track, trigger) => { return { get() { // 告诉vue去追踪数据的变化 track() return value }, set(newValue: T) { clearTimeout(timeOutId) timeOutId = setTimeout(() => { value = newValue // 告诉vue更新界面 trigger() }, delay) } } }) } export default defineComponent({ name: "App", setup() { const keyword = useAntiShake("abc", 3000) return { keyword }; }, }); </script>
# provide 与 inject
-
provide
和
inject提供依赖注入,功能类似 2.x 的
provide/inject -
实现跨层级组件(祖孙)间通信
-
案例:
<template> <h2>provide 与 inject</h2> <p>当前的颜色:{{color}}</p> <button @click="color = 'red'">红色</button> <button @click="color = 'yellow'">黄色</button> <button @click="color = 'blue'">蓝色</button> <hr> <Son /> </template> <script lang="ts"> import { defineComponent, provide, ref } from "vue"; import Son from "./compontent/Son.vue" export default defineComponent({ name: "App", components: { Son }, setup() { const color = ref("red") // 提供数据 provide("color", color) return { color }; }, }); </script>
<template> <h2>子组件Son</h2> <hr> <GrandSon /> </template> <script lang="ts"> import { defineComponent } from "vue"; import GrandSon from "./GrandSon.vue" export default defineComponent({ name: "Son", components: { GrandSon }, setup() { return { }; }, }); </script>
<template> <h3 :style="{color}">孙子组件: {{color}}</h3> </template> <script lang="ts"> import { inject } from 'vue' export default { setup() { const color = inject('color') return { color } } } </script>
# 响应式数据的判断
-
isRef: 检查一个值是否为一个 ref 对象
-
isReactive: 检查一个对象是否是由
reactive
创建的响应式代理 -
isReadonly: 检查一个对象是否是由
readonly
创建的只读代理 -
isProxy: 检查一个对象是否是由
reactive
或者readonly
方法创建的代理<template> <h1></h1> </template> <script lang="ts"> import { defineComponent, isProxy, isReactive, isReadonly, isRef, reactive, readonly, ref } from "vue"; export default defineComponent({ name: "App", setup() { console.log(isRef(ref({}))); console.log(isReactive(reactive({}))); console.log(isReadonly(readonly({}))); console.log(isProxy(reactive({}))); }, }); </script>