欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

vue3原始值響應方案及響應丟失問題解讀

 更新時間:2023年04月20日 08:38:10   作者:cj要學習  
這篇文章主要介紹了vue3原始值響應方案及響應丟失問題解讀,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

前言

我們了解到非原始值是使用 proxy 進行代理的,但是 proxy 無法對 原始值進行代理。vue2中 object.defineproperty 也無法直接截取原始值,但是我們是將數據放入 data 中,對 data 整個對象進行代理,自然就使得 data 中的原始值也能進行響應。

但是 vue3 沒有 data 選項,哪是怎么實現原始值響應的?這就要介紹我們要學的內容了。

注意:下面的實現原理并非是真正的源碼,可以看做是極簡后的源碼核心實現。這樣做的目的是如果放入源碼,源碼非常多且雜,不能一目了然看出其核心原理實現。

一、ref 的引入

ref 就是解決 proxy 無法直接代理原始值的問題。我們先來看 ref 的使用:

const name = ref('小黑子')

ref 是怎么實現的呢?其實就是用對象“包裹”原始值。我們再來看一下 ref 的實現:

function ref(val){
? ? // 使用對象包裹原始值
? ? const wrapper = {
? ? ? ? value:val ? ?
? ? }
? ? // 利用 reactive 將對象變成響應式數據
? ? return reactive(wrapper)
}

ref 的實現就是這么簡單。

ref 對原始值響應主要就做了這兩件事:

  • 1、使用對象包裹原始值。
  • 2、使用 reactive 將包裹對象變?yōu)轫憫綌祿?/li>

二、isref 的實現

我們使用 ref 創(chuàng)建一個響應式對象,但是我們要怎么區(qū)別一個對象是普通對象還是 ref 對象呢?于是我們的 isref 出現了。

我們看一下它的使用:

const name = ref('cj') console.log(isRef(name)); // true

那么它的實現原理是怎樣的呢?主要實現還是在 ref API內部,我們來看一下具體實現代碼:

function ref(val){
? ? const wrapper = {
? ? ? ? value:val ? ?
? ? }
? ? Object.defineProperty(warpper,'__v_isRef',{
? ? ? ? value:true ? ?
? ? })
? ? return reactive(wrapper)
}

原來就是在 ref 內部給 包裹對象添加一個不可枚舉不可寫的屬性,并且值為 true 。這樣我們就可以檢查該屬性來判斷是不是 ref 了。

function isRef(val) {
? ? return val.__v_isRef ?? false
}

三、響應丟失

什么是響應丟失?響應丟失就是響應式數據不進行響應了。我們來看下方代碼:

const obj = reactive({foo:1,bar:2})
const {foo,bar} = obj
obj.foo++ ? ?// foo不會改變,還是 1

上面的 obj 已經響應丟失了,也就不會觸發(fā)重新渲染。為什么會這樣呢?其實就是因為使用了結構賦值,展開運算符也會使其失效。

const obj = reactive({foo:1,bar:2})
const newObj = {...obj}
obj.foo++ ? // newObj.foo不會改變,還是 1

這就相當于重新定義了新的數據,而不再是原來的響應數據了,自然也就不具有響應式能力。

1、toRef登場

toRef 就是為了解決響應丟失的問題。我們來看一下它的實現:

function toRef(obj,key) {
? ? const wrapper = {
? ? ? ? get value() {
? ? ? ? ? ? return obj[key] ? ? ? ?
? ? ? ? },
? ? ? ? set value(val) {
? ? ? ? ? ? obj[key] = val
? ? ? ? } ? ?
? ? }
? ? Object.defineProperty(wrapper,'__v_isRef',{
? ? ? ? value:true ? ?
? ? })
? ? return wrapper
}

傳入兩個參數,第一個是響應式數據,第二個是 obj 的一個鍵。

  • 第一部分就是設置聲明一個對象,對象先設置了 value 屬性的 get 用于將訪問 toRef 值時,將返回傳入的響應式數據對應的屬性值,然后設置了 value屬性的 set 用于將設置 toRef 值時,就拿取設置的新值更新響應式數據對應的屬性值。也就是說,toRef 返回的對象還是利用的響應式數據。
  • 第二部分用于設置返回的數據是 ref 數據。因為 toRef 返回的數據類似 ref 數據,為了統(tǒng)一就直接認定為是一個 ref 數據。
  • 第三部分就是返回響應式數據對應聲明的屬性對象

這樣 toRef 就解決了響應丟失的問題。

2、toRefs 加入

toRefs 就是將整個響應式對象進行解構響應化。實現代碼如下:

function toRefs() {
? ? const ret = {}
? ? for (const key in obj) {
? ? ? ? ret[key] = toRef(obj,key) ? ?
? ? }
? ? return ret
}

使用 for 循環(huán)逐一對屬性進行轉換。這下我們再來看一下使用:

const obj = reactive({foo:1,bar:2})
const {foo,bar} = toRefs(obj)
obj.foo++ ? ?// foo.value變?yōu)?了

3、詭異的其它響應式丟失情況

當屬性為非原始值的時候,解構之后還是依然能響應

const obj = reactive({foo:{age:18},bar:2})
const {foo,bar} = obj
obj.foo.age++ ? ?// foo.age變?yōu)?了
obj.bar++ ? ? ? // bar沒有改變,還是1

這是為什么?原因其實很簡單,因為非原始值賦值的是引用地址,也就是說解構后的變量其實還是指向原響應式數據的屬性。而原始值就是單純的賦值,就不會進行響應。

reactive 響應數據重新賦值后不再響應,ref 響應數據賦值后依然響應
let obj1 = reactive({foo:1,bar:2})
let obj2 = ref({foo:1,bar:2})
?
// 假如 obj1 與 obj2 直接展示在頁面上
obj1 = {boo:2,far:3} ? ?// 頁面 obj1 還是 {foo:1,bar:2}
obj2.value = {boo:2,far:3} ? ?// 頁面 obj2 變?yōu)?{boo:2,far:3} 了? 

這又是什么原因?reactive 重新賦值響應丟失,就是重新賦值了新的對象,自然就成為普通數據了,不再響應。而 ref 還是能響應,是因為 ref 在內部進行 set 處理。代碼如下:

function ref(val){
? ? const wrapper = {
? ? ? ? value:val
? ? ? ? set value(val) { ? ?// isObject 這里代表判斷是否是非原始值的一個方法
? ? ? ? ? ? ?value = isObject(val) === 'Object' ? reactive(val) : val ? ? ??
? ? ? ? }
? ? }
? ? Object.defineProperty(warpper,'__v_isRef',{
? ? ? ? value:true ? ?
? ? })
? ? return reactive(wrapper)
}

我們明白了,其實 ref 在 set 中判斷了設置的新值是否是非原始值,如果是就調用 reactive 將其變?yōu)轫憫綌祿?/p>

四、unref 自動脫 ref       

我們在使用 ref 響應式數據時,會覺得總是需要 .value 來獲取值,增加了用戶的心智負擔。

那可不可以不通過 .value 訪問值,而時直接就能夠訪問值呢?

這樣用于也不用關心某個數據到底是不是 ref 數據,需不需要通過 value 屬性去獲取值。

這就到了我們的 unref 出手了。unref 實現了自動脫 ref 能力,自動脫 ref 就是如果讀取的屬性是一個 ref,則直接將該 ref 對應的 value 屬性值返回。

我們來看一下 unref 的實現:

function unref(target) {
? ? return new Proxy(target,{
? ? ? ? get(target,key,receiver) {
? ? ? ? ? ? const value = Reflect.get(target,key,receiver)
? ? ? ? ? ? return value.__v_isRef ? value.value : value ? ? ? ?
? ? ? ? },
? ? ? ? set(target,key,newValue,receiver) {
? ? ? ? ? ? const value = target[key]
? ? ? ? ? ? if (value.__v_isRef) {
? ? ? ? ? ? ? ? value.value = newValue
? ? ? ? ? ? ? ? return true ? ? ? ? ? ?
? ? ? ? ? ? } ? ? ? ?
? ? ? ? ? ? return Reflect.set(target,key,newValue,receiver)
? ? ? ? }
? ? })
}

我們發(fā)現 unref 內部使用 Proxy 代理了目標對象,接收一個對象作為參數,并返回該對象的代理對象。當我們訪問 unref 的數據時,觸發(fā) get 捕獲器,然后再捕獲器內部判斷了傳入對象是否是 ref 對象,如果是就直接返回 ref 的 .value 值。如果不是則直接返回代理對象。

當對 unref 返回的代理對象設置值時,觸發(fā) set 捕獲器,如果代理的對象時 ref ,就將需要設置的新值賦值給 .value,不是則直接進行賦值處理。

知識擴展

當我們使用 ref 創(chuàng)建響應式數據后,將其在模板中展示,為什么不用 .value 了。

<script setup lang="ts">
import { ref } from 'vue'
const name = ref('小黑子')
</script>
?
<template>
? <div>{{ name }}</div>
</template>

其實原因很簡單,在組件 setup 中聲明的 ref 響應式數據會傳遞給 unref 函數進行處理。所以在模板中訪問 ref 的值,無需通過 value 屬性來訪問。

我們使用的 reactive 其實也是有 自動脫 ref 功能的,看一下下方例子:

const count = ref(0)
const obj = reactive({conut})
?
obj.count ? ?// 0? ? 

我們可以看見 obj.count 是一個 ref 響應式數據。在 count 外層包裹一層對象,再傳遞給 reactive 后,再訪問 obj.count 時就不需要再通過 value 屬性訪問值了。

也正是因為 reactive 內部也同樣實現了自動脫 ref 的能力。

總結

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • vue使用formData時候傳遞參數是個空值的情況處理

    vue使用formData時候傳遞參數是個空值的情況處理

    這篇文章主要介紹了vue使用formData時候傳遞參數是個空值的情況處理,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-05-05
  • el-table-column 內容不自動換行的解決方法

    el-table-column 內容不自動換行的解決方法

    本文主要介紹了el-table-column 內容不自動換行的解決方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-08-08
  • 詳解vue中computed 和 watch的異同

    詳解vue中computed 和 watch的異同

    本篇文章主要介紹了vue中computed 和 watch的異同,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-06-06
  • Vue獲取DOM的幾種方法總結

    Vue獲取DOM的幾種方法總結

    這篇文章主要介紹了Vue獲取DOM的幾種方法總結,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • vue動態(tài)綁定v-model屬性名方式

    vue動態(tài)綁定v-model屬性名方式

    這篇文章主要介紹了vue動態(tài)綁定v-model屬性名方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • Vue 讓元素抖動/擺動起來的實現代碼

    Vue 讓元素抖動/擺動起來的實現代碼

    這篇文章主要介紹了Vue 讓元素抖動/擺動起來的實現代碼,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-05-05
  • Vue NextTick介紹與使用原理

    Vue NextTick介紹與使用原理

    我們對Vue中data數據的修改會導致界面對應的響應變化,而通過nextTick方法,可以在傳入nextTick的回調函數中獲取到變化后的DOM,講起來可能還是有點夢幻,下面我們直接使用nextTick體驗一下效果
    2022-08-08
  • vue基于element-ui的三級CheckBox復選框功能的實現代碼

    vue基于element-ui的三級CheckBox復選框功能的實現代碼

    最近vue項目需要用到三級CheckBox復選框,需要實現全選反選不確定三種狀態(tài)。這篇文章主要介紹了vue基于element-ui的三級CheckBox復選框功能的實現方法,需要的朋友可以參考下
    2018-10-10
  • vue三種模糊查詢方式代碼實例

    vue三種模糊查詢方式代碼實例

    這篇文章主要給大家介紹了關于vue三種模糊查詢方式的相關資料,在vue中模糊搜索主要是用computed屬性實現,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2023-06-06
  • vue實現a標簽點擊高亮方法

    vue實現a標簽點擊高亮方法

    下面小編就為大家分享一篇vue實現a標簽點擊高亮方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-03-03

最新評論