最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Vue3 computed初始化獲取設置值實現示例

 更新時間:2022年10月19日 16:06:18   作者:ClyingDeng  
這篇文章主要為大家介紹了Vue3 computed初始化以及獲取值設置值實現示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

computed 用法

本文給大家?guī)淼氖莢ue3 中 computed API的實現。

大家看過vue3的官網,應該都知道,在vue3 的組合式API中,computed這個功能與以往的有所不同了。

以往vue2 的 computed 用法:

export default {
    components: {
    },
    computed: {
        people() {
            return '這個人' + this.age + '歲'
        }
    },
    watch() {
    },
    data() {
        return {
            age: 1
        }
    }
} 

現在我們大多數情況使用的是組合式 API,可以直接使用computed函數來進行屬性的監(jiān)聽。
比如官網的這種案例寫法:

const count = ref(1) const plusOne = computed(() => count.value + 1) // 只讀屬性
console.log(plusOne.value) // 2

vue3 中的 computed 接受一個 getter 函數,返回一個響應式的ref對象,并且該對象是只讀屬性。讀取該屬性通過 .value 的形式來對外暴露該屬性的值。
此外,如果想要修改該對象,可以傳入一個帶有 get 和 set 函數的對象,通過get 和 set 分別讀取和設置值。
我們來看看這樣的一個簡單的computed用法:

 <div id="app"></div>
<!-- <script src="./reactivity.global.js"></script> -->
    <script src="../../../../node_modules/@vue/reactivity/dist//reactivity.global.js"></script>
 <script>
     const { reactive, effect, computed } = VueReactivity
     const author = reactive({
         name: 'clying',
         sex: '女'
     })
     // 用法一:
     // const introduction = computed({ // 調用的是defineProperty 中的 
     //     // getter
     //     get() {
     //         console.log('run get');
     //         return author.name + '是個' + author.sex + '程序員!'
     //     },
     //     // setter
     //     set(newValue) {
     //         // console.log(newValue);
     //         // 注意:我們這里使用的是解構賦值語法
     //         [author.name, author.sex] = newValue.split(' ')
     //     }
     // })
     // 用法二:
     // 一個計算屬性 ref
     const introduction = computed(() => {
         console.log('run get');
         return author.name + '是個' + author.sex + '程序員!'
     })
     effect(() => {
         app.innerHTML = introduction.value // computed通過 .value 讀取
     })
     introduction.value
     introduction.value
     introduction.value
 </script>

在上述案例中,我們可以很容易就知道,不管讀取introduction幾次,只要值未發(fā)生改變,始終只會輸出一次run get。

computed 實現

那么既然使用vue可以實現,是不是我們也可以自己去搞一個叻?

其實,computed 也是基于effect這個功能函數來實現的。我們可以在我們完成的effect功能上繼續(xù)擴展。

computed 初始化

一步步來,我們先來實現computed的讀取值功能。

const introduction = computed({ // 調用的是defineProperty 中的 
    // getter
    get() {
        console.log('run get');
        return author.name + '是個' + author.sex + '程序員!'
    },
    // setter
    set(newValue) {
        console.log(newValue);
        // 注意:我們這里使用的是解構賦值語法
        [author.name, author.sex] = newValue.split(' ')
    }
})

使用原有的 computed API可以發(fā)現,計算屬性introduction其實是一個ComputedRefImpl類。

那么我們要做的就是先初始化一個類,然后對外暴露其實例。computed可以接收兩種寫法,那么我們在接收參數的時候,需要判斷下用戶傳入的是對象還是一個回調函數。

  • 如果接收的是一個回調函數,那么就只存在取值的get,無法設置值;
  • 如果接收的是一個對象,那么就應該存在取值的get和設置值的set。
export const computed = (getterOrOptions) => {
    let onlyGetter = isFunction(getterOrOptions) // 用戶傳入的回調
    let getter
    let setter
    if (onlyGetter) {
        getter = getterOrOptions
        setter = () => {
            console.warn('no set');
        }
    } else { // 用戶傳入的包含get set函數的對象
        getter = getterOrOptions.get
        setter = getterOrOptions.set
    }
    // ref 引用類型 
    return new ComputedRefImpl(getter, setter)
}

對外暴露的是ComputedRefImpl實例,那么我們初始化還需要在創(chuàng)建一個ComputedRefImpl的類。
ComputedRefImpl類中應該是一個effect,并且應該可以設置個讀取相關的屬性。在屬性訪問器get和set中,它們操作的需要是同一個值,所以我們還需要兩個屬性訪問器操作的同一個值_value,且是私有屬性。
ps:類中的屬性訪問器get和set,底層調用的是Object.defineProperty

class ComputedRefImpl {
    public readonly effect
    private _value// get和set需要使用的同一個值
    constructor(getter, private readonly _setter) {
    }
    get value() {
        return this._value
    }
    set value(newValue) {
        this._setter(newValue)
    }
}

computed 獲取值的實現

值的展示

在我們完成初始化之后,頁面上其實是不會存在我們期望的內容的。它其實是這樣的一個頁面:

必然。我們還沒有將用戶傳入的邏輯進行處理,所以根本看不到呀!

那我們現在要做的就是先將數據展示到頁面上。那我們就先將其effect出來,在讀取值的時候執(zhí)行effect。

class ComputedRefImpl {
    public readonly effect
    private _value// get和set需要使用的同一個值
    constructor(getter, private readonly _setter) {
        this.effect = new ReactiveEffect(getter, () => { })
    }
    get value() {
        this._value = this.effect.run() // 執(zhí)行
        return this._value
    }
    set value(newValue) {
        this._setter(newValue)
    }
}

這樣頁面的數據就可以正常展示了。

but,我們卻忽略了一個問題,在多次讀取時,其實并沒有computed的緩存功能,只是effect正常獲取某個值,獲取一次執(zhí)行一次。

緩存功能

那么,我們要做的就是繼續(xù)完善computed的緩存功能。

既然computed也是響應式的,那么它是一個effect,同時肯定也需要有一個緩存標識,控制它的緩存特性。如果依賴的屬性發(fā)生變化,那么這個緩存標識會更新,重新執(zhí)行get,沒有就不重新執(zhí)行。

定義一個_dirty,默認應該取值的時候進行計算。一開始為true,默認為新值,更新。當執(zhí)行完更新的時候應該將其置稱false,為false時就默認不執(zhí)行更新。

那么除了需要在get讀取值的時候進行判斷,我們還需要依賴屬性發(fā)生變化的時候,再去進行判斷重新渲染,即在構造函數傳入我們的一個調度回調scheduler(我們上篇文章實現的調度函數,在依賴屬性發(fā)生變化的時候,會執(zhí)行我們傳入的回調函數)。

class ComputedRefImpl {
    public readonly effect
    private _value// get和set需要使用的同一個值
    public _dirty = true // 默認應該取值的時候進行計算
    constructor(getter, private readonly _setter) {
        this.effect = new ReactiveEffect(getter, () => {
            //稍后依賴的屬性變化 就會執(zhí)行此調度函數
            if (!this._dirty) {
                this._dirty = true
            }
        })
    }
    get value() {
        if (this._dirty) {
            // 臟數據
            this._dirty = false
            this._value = this.effect.run() // 執(zhí)行
        }
        return this._value
    }
    set value(newValue) {
        this._setter(newValue)
    }
}

我們可以看到,此時introduction值未發(fā)生變化,就只會執(zhí)行一次effet。

computed 設置值實現

修改值,我們可以通過上述用法一來傳入一個帶有set和get函數的對象,在設置值的時候通過解構的方式進行賦值。

在 computed 中的set時,我們可以拿到computed的新值,但并沒有重新渲染更新頁面。此時我們需要做的就是將computed相關的屬性進行依賴的收集,并在發(fā)生變化的時候進行相應的依賴觸發(fā)。與effect類似。

既然類似effect,那我們就需要一個存放依賴的dep(在類中定義public dep = undefined),get時收集,屬性變化時觸發(fā)。

// ComputedRefImpl 類
get value() {
    trackEffects(this.dep || (this.dep = new Set())) // 收集
    if (this._dirty) {
        // 臟數據
        this._dirty = false
        this._value = this.effect.run() // 執(zhí)行
    }
    return this._value
}
// ComputedRefImpl 類
constructor(getter, private readonly _setter) {
    this.effect = new ReactiveEffect(getter, () => {
        //稍后依賴的屬性變化 就會執(zhí)行此調度函數
        if (!this._dirty) {
            this._dirty = true
            // 觸發(fā)更新
            triggerEffects(this.dep)
        }
    })
}

其中收集trackEffects和觸發(fā)triggerEffects就是將effect中的tracktrigger中部分共用功能提取出來了。

比如收集的這個功能trackEffects。與effect類似,我們都需要將記錄相應的依賴屬性和依賴屬性的effect,那我們就可以將其獨立成一個新的功能函數,降低耦合度。

export function track(target, type, key) {
    // 收集effect中 屬性對應的effect
    if (!activeEffect) return
    let depsMap = targetMap.get(target)
    if (!depsMap) {
        targetMap.set(target, (depsMap = new Map()))
    }
    let dep = depsMap.get(key)
    if (!dep) { depsMap.set(key, (dep = new Set())) }
    // 判斷去重 set中是否存在activeEffect
    trackEffects(dep)
}
// 將set存起來
export function trackEffects(dep) {
    if (!activeEffect) return
    let shouldTrack = !dep.has(activeEffect) // 不存在
    if (shouldTrack) {
        dep.add(activeEffect) // 屬性記錄effect 
        // 反向記錄 effect記錄哪些屬性收集過
        activeEffect.deps.push(dep) // 讓activeEffect 記錄住對應的dep 稍后清理會用到
    }
}

triggerEffects也是如此:

export function trigger(target, type, key, value, oldValue) {
    // 判斷targetMap是否存在target
    // 不存在 直接返回 不需要收集
    // 存在 取depsMap中對應key的effect 執(zhí)行run
    const depsMap = targetMap.get(target)
    if (!depsMap) return
    let effects = depsMap.get(key)
    if (effects) {
        triggerEffects(effects)
    }
}
export function triggerEffects(effects) {
    effects = [...effects] // effects 中 set結構刪除再添加會導致死循環(huán)
    effects.forEach(effect => {
        // 在執(zhí)行effect時,又要執(zhí)行自己,需要屏蔽自己的effect
        if (effect !== activeEffect) {
            if (effect.scheduler)
                effect.scheduler() // 如果存在自己的調度函數就執(zhí)行自己的scheduler
            else effect.run() // 否則就執(zhí)行run
        }
    });
}

上述只是vue3中computed的簡版實現方式,源碼中比我們實現的考慮的要多很多,有興趣的可以自己去看看(源碼路徑:packages/reactivity/src/computed.ts):

最后,我們也可以看到,頁面上過了1秒之后,相應的屬性變化,頁面也同樣發(fā)生了變化??????。

其實,computed的核心就是effect + 緩存 + 依賴收集、觸發(fā)

以上就是Vue3 computed初始化獲取設置值實現示例的詳細內容,更多關于Vue3 computed值設置獲取的資料請關注腳本之家其它相關文章!

相關文章

  • 使用Vue開發(fā)自己的Chrome擴展程序過程詳解

    使用Vue開發(fā)自己的Chrome擴展程序過程詳解

    這篇文章主要介紹了使用Vue開發(fā)自己的Chrome擴展程序過程詳解,瀏覽器擴展程序是可以修改和增強 Web 瀏覽器功能的小程序。它們可用于各種任務,例如阻止廣告,管理密碼,組織標簽,改變網頁的外觀和行為等等。,需要的朋友可以參考下
    2019-06-06
  • 一文搞懂VueJs中customRef函數使用

    一文搞懂VueJs中customRef函數使用

    這篇文章主要為大家介紹了VueJs中customRef函數使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-04-04
  • vue3的基本使用方法詳細教程

    vue3的基本使用方法詳細教程

    這篇文章主要介紹了vue3的基本使用方法,結合實例形式詳細分析了vue3功能、組件、生命周期、TypeScript結合運用等相關概念與使用方法,需要的朋友可以參考下
    2023-06-06
  • vue 解決兄弟組件、跨組件深層次的通信操作

    vue 解決兄弟組件、跨組件深層次的通信操作

    這篇文章主要介紹了vue 解決兄弟組件、跨組件深層次的通信操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-07-07
  • Vue項目打包編譯優(yōu)化方案

    Vue項目打包編譯優(yōu)化方案

    當一個較復雜的vue項目打包后,文件會非常大,而且訪問時資源加載速度很慢,本文介紹了幾種措施來優(yōu)化。
    2020-09-09
  • vue3中組件事件和defineEmits示例代碼

    vue3中組件事件和defineEmits示例代碼

    這篇文章主要給大家介紹了關于vue3中組件事件和defineEmits的相關資料,組件事件是Vue組件之間進行通信的一種方式,文中通過代碼示例介紹的非常詳細,需要的朋友可以參考下
    2023-10-10
  • el-date-picker日期選擇限制范圍的實例代碼

    el-date-picker日期選擇限制范圍的實例代碼

    這篇文章主要介紹了el-date-picker日期選擇限制范圍,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-09-09
  • vue加載自定義的js文件方法

    vue加載自定義的js文件方法

    下面小編就為大家分享一篇vue加載自定義的js文件方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-03-03
  • vue如何直接獲取url中的參數

    vue如何直接獲取url中的參數

    這篇文章主要介紹了vue如何直接獲取url中的參數問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • vue-socket.io跨域問題有效解決方法

    vue-socket.io跨域問題有效解決方法

    在本篇文章里小編給大家整理的是關于vue-socket.io跨域問題有效解決方法,對此有興趣的朋友們可以參考下。
    2020-02-02

最新評論

海南省| 安义县| 星子县| 收藏| 墨江| 馆陶县| 宜兰县| 哈巴河县| 义乌市| 土默特左旗| 改则县| 巴青县| 弥勒县| 利津县| 如东县| 庄浪县| 渝中区| 赤壁市| 吴江市| 三江| 蓝山县| 耒阳市| 磐石市| 祁连县| 宜都市| 新密市| 马鞍山市| 阿拉善盟| 攀枝花市| 青岛市| 英吉沙县| 鄂州市| 延长县| 辽源市| 龙门县| 满洲里市| 临高县| 达日县| 舒兰市| 泗水县| 昆明市|