Vue Ref全家桶具體用法詳解
1. ref
在Vue3中,ref成為了一個(gè)全家桶,除了用于創(chuàng)建響應(yīng)式數(shù)據(jù)之外,還可以用于引用DOM元素、組件實(shí)例和其他對(duì)象。以下是ref的具體用法:
1.1. 創(chuàng)建響應(yīng)式數(shù)據(jù)
我們可以使用ref函數(shù)來(lái)創(chuàng)建響應(yīng)式數(shù)據(jù),例如:
<template>
<div>{{ count }}</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const count = ref(0)
console.log(count.value) // 輸出 0
count.value += 1
console.log(count.value) // 輸出 1
</script>
<style scoped>
</style>
注意被ref包裝之后需要.value 來(lái)進(jìn)行賦值
在這個(gè)例子中,我們使用ref函數(shù)來(lái)創(chuàng)建一個(gè)響應(yīng)式數(shù)據(jù)count,初始值為0。我們可以使用count.value來(lái)訪問(wèn)和修改這個(gè)值。
1.2. 引用DOM元素
我們可以使用ref函數(shù)來(lái)引用DOM元素,例如:
<template>
<div ref="container"></div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
const container = ref(null) // 注意:此處的變量名必須和標(biāo)簽上的屬性名一致
onMounted(() => {
console.log(container.value) // 輸出 <div></div>
})
</script>
<style scoped>
</style>
在這個(gè)例子中,我們使用ref函數(shù)來(lái)創(chuàng)建一個(gè)container引用,然后在模板中使用ref="container"來(lái)將這個(gè)引用綁定到一個(gè)<div>元素上。在setup函數(shù)中,我們使用onMounted鉤子來(lái)訪問(wèn)這個(gè)引用的值。
1.3. 引用組件實(shí)例
我們可以使用ref函數(shù)來(lái)引用組件實(shí)例,例如:
<template>
<Child ref="child" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import Child from './Child.vue'
const child = ref(null)
</script>
<style scoped>
</style>
在這個(gè)例子中,我們使用ref函數(shù)來(lái)創(chuàng)建一個(gè)child引用,然后將這個(gè)引用綁定到一個(gè)<Child>組件上。在script中,我們將這個(gè)引用暴露出去,以便在其他地方使用。
1.4. 引用其他對(duì)象
除了DOM元素和組件實(shí)例之外,我們還可以使用ref函數(shù)來(lái)引用其他對(duì)象,例如:
<template>
<Child ref="child" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
const data = { name: 'John' }
const obj = ref(data)
console.log(obj.value.name) // 輸出 'John'
obj.value.name = 'Mary'
console.log(data.name) // 輸出 'Mary'
<script>
<style scoped>
</style>
在這個(gè)例子中,我們使用ref函數(shù)來(lái)引用一個(gè)對(duì)象data,然后將這個(gè)引用賦值給一個(gè)obj變量。我們可以使用obj.value來(lái)訪問(wèn)和修改這個(gè)對(duì)象。在這個(gè)例子中,我們將obj.value.name修改為Mary,然后發(fā)現(xiàn)data.name也被修改了。
1.5. ref源碼
在Vue3中,ref函數(shù)的源碼如下:
import { isObject } from '@vue/shared'
import { ReactiveFlags, reactive } from './reactive'
export function ref(value) {
// 如果value已經(jīng)是一個(gè)ref對(duì)象,直接返回它
if (isRef(value)) {
return value
}
// 創(chuàng)建一個(gè)響應(yīng)式對(duì)象
let valueIsObject = isObject(value)
const ref = {
// 標(biāo)記這個(gè)對(duì)象是一個(gè)ref對(duì)象
[ReactiveFlags.IS_REF]: true,
// 獲取ref的值
get value() {
// 如果value是一個(gè)對(duì)象,則返回一個(gè)響應(yīng)式對(duì)象
if (valueIsObject) {
return reactive(value)
}
return value
},
// 設(shè)置ref的值
set value(newVal) {
if (valueIsObject) {
value = newVal
valueIsObject = isObject(newVal)
return
}
// 如果value是一個(gè)基本類型的值,則直接修改它
value = newVal
}
}
return ref
}
在這個(gè)源碼中,ref函數(shù)首先會(huì)判斷傳入的值是否已經(jīng)是一個(gè)ref對(duì)象,如果是則直接返回它,否則會(huì)創(chuàng)建一個(gè)響應(yīng)式對(duì)象來(lái)作為ref對(duì)象的值。然后ref函數(shù)會(huì)返回一個(gè)擁有value屬性的對(duì)象,當(dāng)讀取這個(gè)屬性時(shí),如果它的值是一個(gè)對(duì)象,則會(huì)返回一個(gè)響應(yīng)式對(duì)象,否則直接返回它的值;當(dāng)修改這個(gè)屬性時(shí),如果它的值是一個(gè)對(duì)象,則會(huì)將新值轉(zhuǎn)化為響應(yīng)式對(duì)象,否則直接修改它的值。
2. isRef
在Vue3中,isRef函數(shù)用于判斷一個(gè)對(duì)象是否為ref對(duì)象,它通過(guò)判斷這個(gè)對(duì)象是否擁有一個(gè)特殊的屬性IS_REF來(lái)進(jìn)行判斷。這個(gè)特殊屬性的值為true,表示這個(gè)對(duì)象是一個(gè)ref對(duì)象。
2.1. isRef的使用
<template>
<div class="wrapper"></div>
</template>
<script setup lang="ts">
import { isRef, ref } from 'vue';
const name: string = '張三';
console.log(isRef(name)); // false
const age = ref(10);
console.log(isRef(age)); // true
</script>
<style scoped>
</style>
2.2. isRef源碼
// 判斷一個(gè)對(duì)象是否為ref對(duì)象
export function isRef(r) {
return Boolean(r && r[ReactiveFlags.IS_REF])
}
3. shallowRef
在Vue3中shallowRef函數(shù),用于創(chuàng)建一個(gè)“淺層”的響應(yīng)式對(duì)象。
與ref函數(shù)不同的是,shallowRef函數(shù)不會(huì)將其值轉(zhuǎn)化為響應(yīng)式對(duì)象,而是直接將其作為普通的對(duì)象或數(shù)組來(lái)處理。這意味著,當(dāng)修改shallowRef對(duì)象的屬性或數(shù)組的元素時(shí),Vue3將不會(huì)追蹤這些變化。這種“淺層”的響應(yīng)式對(duì)象對(duì)于一些不需要完全響應(yīng)式的場(chǎng)景非常有用,例如緩存一些數(shù)據(jù)或跟蹤某些狀態(tài)。
3.1. shallowRef的使用
下面是一個(gè)使用shallowRef函數(shù)的示例:
<template>
<div>{{ obj.name }}</div>
</template>
<script setup lang="ts">
import { shallowRef } from 'vue'
const obj = { name: 'John', age: 30 }
const ref = shallowRef(obj)
console.log(ref.value.name) // 輸出 'John'
ref.value.name = 'Mary'
console.log(obj.name) // 輸出 'Mary'
</script>
<style scoped>
</style>
在這個(gè)示例中,我們使用shallowRef函數(shù)來(lái)創(chuàng)建一個(gè)“淺層”的響應(yīng)式對(duì)象ref,并將其值設(shè)置為obj對(duì)象。當(dāng)我們修改ref.value.name屬性的值時(shí),obj.name屬性的值也發(fā)生了改變。這是因?yàn)?code>obj對(duì)象和ref對(duì)象共享同一個(gè)引用。
3.2. shallowRef的源碼
在Vue3中,shallowRef函數(shù)的源碼如下:
import { isObject, toRawType } from '@vue/shared'
import { track, trigger } from './effect'
import { ReactiveFlags } from './reactive'
const shallowGet = (value) => value
const shallowSet = () => {
console.warn(
`Value assigned to a shallow ref ${String(value)} is not reactive, ` +
`expecting explicitly passing deep: true in ref() options`
)
}
class ShallowRefImpl {
public readonly __v_isRef = true
public readonly [ReactiveFlags.IS_SHALLOW] = true
constructor(public _value) {}
get value() {
track(this, 'get', 'value')
return this._value
}
set value(newValue) {
if (newValue !== this._value) {
this._value = newValue
trigger(this, 'set', 'value', newValue)
}
}
}
export function shallowRef(value) {
return new ShallowRefImpl(value)
}
export function isShallowRef(value) {
return !!value[ReactiveFlags.IS_SHALLOW]
}
shallowRef函數(shù)會(huì)創(chuàng)建一個(gè)ShallowRefImpl對(duì)象,并將傳入的值作為其內(nèi)部的_value屬性的值。ShallowRefImpl對(duì)象是一個(gè)帶有get和set方法的普通對(duì)象,當(dāng)讀取value屬性時(shí),get方法會(huì)返回_value屬性的值;當(dāng)修改value屬性時(shí),set方法會(huì)將新值賦值給_value屬性,并觸發(fā)相應(yīng)的依賴。
4.triggerRef
強(qiáng)制更新DOM
4.1. triggerRef的使用
triggerRef的使用非常簡(jiǎn)單,只需要傳遞一個(gè)Ref對(duì)象作為參數(shù)即可。例如:
import { ref, triggerRef } from 'vue'
const count = ref(0)
// 在某些情況下需要手動(dòng)更新count,可以使用triggerRef
triggerRef(count)
在這個(gè)例子中,我們使用ref函數(shù)創(chuàng)建了一個(gè)名為count的響應(yīng)式引用,它的初始值為0。然后我們?cè)谀承┣闆r下需要手動(dòng)更新count,這時(shí)我們可以使用triggerRef函數(shù)來(lái)觸發(fā)它的更新。
需要注意的是,當(dāng)使用triggerRef函數(shù)觸發(fā)更新時(shí),它只會(huì)更新Ref對(duì)象本身,而不會(huì)更新與之相關(guān)聯(lián)的組件。因此,我們應(yīng)該在明確知道需要手動(dòng)更新時(shí)使用triggerRef函數(shù),而在普通情況下使用Vue自身的響應(yīng)式系統(tǒng)來(lái)自動(dòng)更新相關(guān)組件。
4.2. triggerRef的源碼實(shí)現(xiàn)
在Vue3中,triggerRef函數(shù)用于觸發(fā)一個(gè)ref對(duì)象的依賴更新。其源碼如下:
import { effect } from './effect'
import { track, trigger } from './operations'
export function triggerRef(ref) {
if (ref.__v_isRef) {
const value = ref.value
if (isTracking()) {
track(ref, 'set', 'value')
}
ref.value = value
trigger(ref, 'set', 'value', value)
} else {
console.warn(`triggerRef() expects a ref object passed as its argument.`)
}
}
在這個(gè)源碼中,首先判斷傳入的對(duì)象是否為ref對(duì)象,如果是則獲取它的值,并使用track函數(shù)追蹤這個(gè)ref對(duì)象的依賴。然后將這個(gè)ref對(duì)象的值賦值給它自己的value屬性,并使用trigger函數(shù)觸發(fā)這個(gè)ref對(duì)象的依賴更新。如果傳入的對(duì)象不是ref對(duì)象,則會(huì)輸出一個(gè)警告信息。
5. customRef
在 Vue 3 中,提供了一個(gè) customRef 函數(shù),用于創(chuàng)建一個(gè)自定義的、可響應(yīng)的引用對(duì)象。與 ref 和 shallowRef 不同的是,customRef 可以自定義 get 和 set 方法的實(shí)現(xiàn)邏輯,從而實(shí)現(xiàn)更加靈活的響應(yīng)式行為。
使用 customRef 函數(shù)創(chuàng)建的引用對(duì)象與 ref 對(duì)象類似,也具有 value 屬性,當(dāng)讀取這個(gè)屬性時(shí),會(huì)觸發(fā) get 方法的執(zhí)行;當(dāng)修改這個(gè)屬性時(shí),會(huì)觸發(fā) set 方法的執(zhí)行,并且會(huì)觸發(fā)相應(yīng)的依賴更新。與 ref 對(duì)象不同的是,customRef 函數(shù)本身并不會(huì)對(duì)傳入的初始值進(jìn)行處理,而是將其直接作為 get 方法的返回值,需要自己手動(dòng)處理。
下面是 customRef 函數(shù)的使用示例:
5.1. customRef使用
import { customRef } from 'vue'
const myRef = customRef((track, trigger) => ({
value: 0,
get() {
track()
return this.value
},
set(newValue) {
this.value = newValue
trigger()
}
}))
console.log(myRef.value) // 輸出 0
myRef.value = 1
console.log(myRef.value) // 輸出 1
在這個(gè)示例中,使用 customRef 函數(shù)創(chuàng)建了一個(gè)自定義的引用對(duì)象 myRef,它的 get 方法用于追蹤依賴,返回 value 屬性的值;set 方法用于修改 value 屬性的值,并觸發(fā)相應(yīng)的依賴更新。當(dāng)讀取和修改 myRef 對(duì)象的 value 屬性時(shí),會(huì)分別觸發(fā)它的 get 和 set 方法。
注意:customRef 函數(shù)的參數(shù)是一個(gè)函數(shù),這個(gè)函數(shù)接收兩個(gè)參數(shù),分別是 track 和 trigger 函數(shù),它們用于追蹤依賴和觸發(fā)依賴更新。
5.2. customRef 函數(shù)的源代碼
import { track, trigger } from './effect'
export function customRef(factory) {
const ref = {
__v_isRef: true,
get value() {
return factory().get()
},
set value(newValue) {
factory().set(newValue)
}
}
return ref
}
export function triggerRef(ref) {
trigger(ref, 'set', 'value', ref.value)
}
在這個(gè)源碼中,定義了一個(gè) customRef 函數(shù),它接收一個(gè)工廠函數(shù)作為參數(shù),用于創(chuàng)建一個(gè)自定義的引用對(duì)象。在函數(shù)內(nèi)部,創(chuàng)建了一個(gè)普通的對(duì)象 ref,它有一個(gè)只讀的 __v_isRef 屬性,用于標(biāo)識(shí)它是一個(gè) ref 對(duì)象;還有一個(gè)名為 value 的屬性,用于存儲(chǔ)引用對(duì)象的值,并且在讀取和修改時(shí)會(huì)觸發(fā)工廠函數(shù)的 get 和 set 方法。在 customRef 函數(shù)的最后,返回這個(gè) ref 對(duì)象。
總結(jié):這篇文章介紹了Vue3中的ref函數(shù)、isRef函數(shù)、shallowRef函數(shù)和customRef函數(shù)。ref函數(shù)主要用于創(chuàng)建響應(yīng)式對(duì)象,引用DOM實(shí)例,引用組件實(shí)例等。isRef函數(shù)主要用于判斷傳入的數(shù)據(jù)是不是響應(yīng)式對(duì)象。shallowRef函數(shù)創(chuàng)建一個(gè)“淺層”的響應(yīng)式對(duì)象,只追蹤值的屬性變化,而不追蹤對(duì)象內(nèi)部屬性的變化。customRef函數(shù)可以創(chuàng)建自定義的引用對(duì)象,可以自定義get和set方法的實(shí)現(xiàn)邏輯。此外,文章還介紹了triggerRef函數(shù),用于觸發(fā)ref對(duì)象的依賴更新。
到此這篇關(guān)于Vue Ref全家桶具體用法詳解的文章就介紹到這了,更多相關(guān)Vue Ref內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Element Plus暗黑模式及模式自由切換的實(shí)現(xiàn)
本文詳細(xì)介紹了如何在使用Vite構(gòu)建的Vue項(xiàng)目中實(shí)現(xiàn)ElementPlus暗黑模式及模式切換,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-11-11
vue項(xiàng)目中跳轉(zhuǎn)到外部鏈接的實(shí)例講解
今天小編就為大家分享一篇vue項(xiàng)目中跳轉(zhuǎn)到外部鏈接的實(shí)例講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-09-09
vue如何動(dòng)態(tài)實(shí)時(shí)的顯示時(shí)間淺析
這篇文章主要給大家介紹了關(guān)于vue如何動(dòng)態(tài)實(shí)時(shí)的顯示時(shí)間,以及vue時(shí)間戳 獲取本地時(shí)間實(shí)時(shí)更新的相關(guān)資料,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-05-05
vue-router傳遞參數(shù)的幾種方式實(shí)例詳解
vue-router傳遞參數(shù)分為兩大類,一類是編程式的導(dǎo)航 router.push另一類是聲明式的導(dǎo)航 <router-link>,本文通過(guò)實(shí)例代碼給大家介紹vue-router傳遞參數(shù)的幾種方式,感興趣的朋友跟隨小編一起看看吧2018-11-11
vue實(shí)現(xiàn)跨頁(yè)面定位錨點(diǎn)區(qū)域方式
這篇文章主要介紹了vue實(shí)現(xiàn)跨頁(yè)面定位錨點(diǎn)區(qū)域方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-05-05
vue打包部署到springboot并通過(guò)tomcat運(yùn)行的操作方法
這篇文章主要介紹了vue打包部署到springboot并通過(guò)tomcat運(yùn)行的操作方法,本文通過(guò)實(shí)例圖文并茂的形式給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-05-05
Vue如何通過(guò)瀏覽器控制臺(tái)查看全局data值
在寫vue項(xiàng)目時(shí)想到一個(gè)問(wèn)題,項(xiàng)目里面的文件都是一個(gè)個(gè)的組件,如何在控制臺(tái)中修改,查看組件data里的值呢,下面這篇文章主要給大家介紹了關(guān)于Vue如何通過(guò)瀏覽器控制臺(tái)查看全局data值的相關(guān)資料,需要的朋友可以參考下2023-04-04
vue實(shí)現(xiàn)列表無(wú)縫滾動(dòng)
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)列表無(wú)縫滾動(dòng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-06-06

