1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        讓Vue3 Composition API 存在于你 Vue 以外的項目中

        共 7376字,需瀏覽 15分鐘

         ·

        2020-10-12 21:45

        • 作者:陳大魚頭
        • github:KRISACHAN

        作為新特性 Composition API ,在 Vue3 正式發(fā)布之前一段時間就發(fā)布過了。

        據(jù)文檔介紹, Composition API 是一組低侵入式的、函數(shù)式的 API,使得我們能夠更靈活地「組合」組件的邏輯。

        不僅在 Vue 中,在其他的框架或原生 JS 也可以很好地被使用,下面我們就選取幾個比較重要的 Composition API ,通過一些簡單的例子來看看如何在其他項目中使用。

        注:本文僅列出各個分類下比較重要的 API,想要查看全部可以點擊下方鏈接進行查看:

        https://github.com/vuejs/vue-next/tree/master/packages/reactivity

        reactive API

        createReactiveObject

        createReactiveObject 函數(shù)是 reactive API 的核心,用于創(chuàng)建 ?reactive 對象 。

        在分享 API 之前,我們先看看其核心實現(xiàn),由于篇幅有限,本文僅展示出理解后的簡化版代碼,代碼如下:

        function?createReactiveObject(
        ??target,?//?要監(jiān)聽目標
        ??isReadonly,?//?是否只讀
        ??baseHandlers,?//?target?為?Object?或?Array?時的處理器,支持對數(shù)據(jù)的增刪改查
        ??collectionHandlers?//?target?為?Map/WeakMap?或?Set/WeakSet?時的處理器,支持對數(shù)據(jù)的增刪改查
        )?
        {
        ????if?(target[ReactiveFlags.RAW]?&&?!(isReadonly?&&?target[ReactiveFlags.IS_REACTIVE])?{
        ??????//?當?target?已經是一個?Proxy?時,直接返回
        ??????//?例外情況:在 Proxy 里調用 readonly()
        ?????return?target
        ????}
        ????//?當前對象已被監(jiān)聽過時,就直接返回被監(jiān)聽的對象
        ????if?(existingProxy)?{
        ??????return?existingProxy
        ????}
        ????//?如果是?Object?Array?Map/WeakMap?Set/WeakSet?以外只能監(jiān)聽到值的數(shù)據(jù),直接返回
        ????if?(targetType?===?TargetType.INVALID)?{
        ??????return?target
        ????}
        ????//?根據(jù)參數(shù)類型生成對應的?Proxy?對象,以及添加對應的處理器
        ????const?proxy?=?new?Proxy(
        ??????target,
        ??????targetType?===?TargetType.COLLECTION???collectionHandlers?:?baseHandlers
        ????)
        ????proxyMap.set(target,?proxy)
        ????return?proxy
        }

        reactive

        接收一個普通對象然后返回該普通對象的響應式代理。等同于 2.x 的 Vue.observable()

        示例如下:

        import?{
        ??reactive,
        ??isReactive?//?判斷是否是?reactive?對象
        }?from?'https://unpkg.com/@vue/reactivity/dist/reactivity.esm-browser.js'
        const?obj?=?{
        ??nested:?{
        ????foo:?1
        ??},
        ??array:?[{?bar:?2?}]
        }
        const?value?=?10

        const?observedObj?=?reactive(obj)
        const?observedValue?=?reactive(value)

        console.log(isReactive(observedObj))?//?true
        console.log(isReactive(observedValue))?//?true

        shallowReactive

        只為某個對象的私有(第一層)屬性創(chuàng)建淺層的響應式代理,不會對“屬性的屬性”做深層次、遞歸響應式代理,而只是保留原樣。

        示例如下:

        const?obj?=?{
        ??nested:?{
        ????foo:?1
        ??},
        ??array:?[{?bar:?2?}]
        }
        const?value?=?10

        const?unobservedObj?=?shallowReactive(obj)
        const?unobservedValue?=?shallowReactive(value)

        console.log(isReactive(observedObj))?//?false
        console.log(isReactive(observedValue))?//?false

        effect API

        createReactiveEffect

        createReactiveEffect 是 effect API 的核心,用于創(chuàng)建監(jiān)聽用戶自定義的 reactive 對象的函數(shù)

        在分享 API 之前,我們先看看其核心實現(xiàn),由于篇幅有限,本文僅展示出理解后的簡化版代碼,代碼如下:

        function?createReactiveEffect(
        ?fn,?//?用戶創(chuàng)建的?reactive?對象變動執(zhí)行回調
        ??options?=?{
        ????lazy,?//?是否執(zhí)行用戶函數(shù)
        ????scheduler,?//?收集數(shù)據(jù)記錄
        ????onTrack,?//?追蹤用戶數(shù)據(jù)的回調
        ????onTrigger,?//?追蹤變更記錄
        ????onStop,?//?停止執(zhí)行
        ????allowRecurse?//?是否允許遞歸
        ??}
        )?
        {
        ????const?effect?=?function?reactiveEffect()?{
        ??????if?(!effectStack.includes(effect))?{
        ????????cleanup(effect)?//?清空?effect
        ????????try?{
        ??????????enableTracking()?//?往追蹤用戶數(shù)據(jù)的棧內添加當前?effect
        ??????????effectStack.push(effect)?//?往?effect?棧內添加?effect
        ??????????activeEffect?=?effect?//?將活動?effect?變成當前?effect
        ??????????return?fn()?//?執(zhí)行回調
        ????????}?finally?{?//?刪除當前記錄
        ??????????effectStack.pop()
        ??????????resetTracking()
        ??????????activeEffect?=?effectStack[effectStack.length?-?1]
        ????????}
        ??????}
        ????}
        ??effect.id?=?uid++
        ????effect._isEffect?=?true
        ????effect.active?=?true
        ????effect.raw?=?fn
        ????effect.deps?=?[]
        ????effect.options?=?options
        ????return?effect
        }

        effect

        effect 函數(shù)是 effect API 的核心。以 WeakMap 為數(shù)據(jù)類型,是一個用于存儲用戶自定義函數(shù)的 訂閱者。

        示例如下:

        let?dummy
        const?counter?=?reactive({?num:?0?})
        effect(()?=>?(dummy?=?counter.num))
        console.log(dummy?===?0)?//?true
        counter.num?=?7
        console.log(dummy?===?7)?//?true

        ref API

        RefImpl

        RefImpl 是 ref API 的核心,用于創(chuàng)建 ref 對象

        在分享 API 之前,我們先看看其核心實現(xiàn),代碼如下:

        class?RefImpl?{
        ??private?_value?//?存儲當前?ref?對象的值

        ??public?__v_isRef?=?true?//?確定是否為?ref?對象的變量?(只讀)

        ??constructor(
        ????private?_rawValue,?//?用戶傳入的原始值
        ????public?readonly?_shallow?=?false?//?當前?ref?對象是否為?shallowRef
        ??)?{
        ????// convert:如果傳入的原始值為對象,則會被 convert 函數(shù)轉換為 reactive 對象
        ????this._value?=?_shallow???_rawValue?:?convert(_rawValue)
        ??}

        ??get?value()?{
        ????//?用于追蹤用戶輸入的值變化
        ????// track:effect api 的 track 函數(shù),用于追蹤用戶行為,當前則是追蹤用戶的 get 操作
        ????// toRaw:effect api 的 toRaw 函數(shù),將 this 轉化為用戶輸入值
        ????track(toRaw(this),?TrackOpTypes.GET,?'value')
        ????return?this._value
        ??}

        ??set?value(newVal)?{
        ????if?(hasChanged(toRaw(newVal),?this._rawValue))?{
        ??????//?當前?ref?對象有變化時
        ??????//?_rawValue?/?_value?變更
        ??????// trigger:effect api 的 trigger 函數(shù),根據(jù)用戶傳入的值與操作類型來進行操作,當前則為將用戶傳入的值添加到值 map 里
        ??????this._rawValue?=?newVal
        ??????this._value?=?this._shallow???newVal?:?convert(newVal)
        ??????trigger(toRaw(this),?TriggerOpTypes.SET,?'value',?newVal)
        ????}
        ??}
        }

        ref

        接受一個參數(shù)值并返回一個響應式且可改變的 ref 對象。ref 對象擁有一個指向內部值的單一屬性 .value。如果傳入 ref 的是一個對象,將調用 reactive 方法進行深層響應轉換。

        示例如下:

        const?count?=?ref({
        ??name:?'魚頭',
        ??type:?'帥哥'
        })
        console.log(count.value.type)?//?帥哥
        count.value.type?=?'超級大帥哥'
        console.log(count.value.type)?//?超級大帥哥

        shallowRef

        創(chuàng)建一個 ref ,將會追蹤它的 .value 更改操作,但是并不會對變更后的 .value 做響應式代理轉換(即變更不會調用 reactive

        示例如下:

        const?__shallowRef?=?shallowRef({?a:?1?})
        let?dummy
        effect(()?=>?{
        ??dummy?=?__shallowRef.value.a
        })
        console.log(dummy)?//?1

        __shallowRef.value.a?=?2
        console.log(dummy)?//?1
        console.log(isReactive(__shallowRef.value))?//?false

        customRef

        customRef 用于自定義一個 ref,可以顯式地控制依賴追蹤和觸發(fā)響應,接受一個工廠函數(shù),兩個參數(shù)分別是用于追蹤的 track 與用于觸發(fā)響應的 trigger,并返回一個帶有 getset 屬性的對象。

        示例如下:

        let?value?=?1
        let?_trigger

        const?custom?=?customRef((track,?trigger)?=>?({
        ??get()?{
        ????track()
        ????return?value
        ??},
        ??set(newValue)?{
        ????value?=?newValue
        ????_trigger?=?trigger
        ??}
        }))

        let?dummy
        effect(()?=>?{
        ??dummy?=?custom.value
        })
        console.log(dummy)?//?1

        custom.value?=?2
        console.log(dummy)?//?1

        _trigger()
        console.log(dummy)?//?2

        triggerRef

        triggerRef 用于主動觸發(fā) shallowRef

        示例如下:

        const?__shallowRef?=?shallowRef({?a:?1?})
        let?dummy
        effect(()?=>?{
        ??dummy?=?__shallowRef.value.a
        })
        console.log(dummy)?//?1

        __shallowRef.value.a?=?2
        console.log(dummy)?//?1
        console.log(isReactive(__shallowRef.value))?//?false

        triggerRef(__shallowRef)
        console.log(dummy)?//?2

        computed API

        ComputedRefImpl

        ComputedRefImpl 是 ref API 的核心,用于創(chuàng)建 computed 對象

        在分享 API 之前,我們先看看其核心實現(xiàn),由于篇幅有限,本文僅展示出理解后的簡化版代碼,代碼如下:

        class?ComputedRefImpl?{
        ??private?_value?//?當前值
        ??private?_dirty?=?true?//?當前值是否發(fā)生過變更

        ??public?effect?//?effect?對象

        ??public?__v_isRef?=?true;?//?指定為?ref?對象
        ??public?[ReactiveFlags.IS_READONLY]:?boolean?//?是否只讀

        ??constructor(
        ????getter,?//?getter
        ????private?_setter,?//?setter
        ????isReadonly?//?是否只讀
        ??)?{
        ????this.effect?=?effect(getter,?{
        ??????lazy:?true,
        ??????scheduler:?()?=>?{
        ????????if?(!this._dirty)?{
        ??????????//?將變更狀態(tài)變?yōu)?true
        ??????????// trigger:effect api 的 trigger 函數(shù),根據(jù)用戶傳入的值與操作類型來進行操作,當前則為將用戶傳入的值添加到值 map 里
        ??????????this._dirty?=?true
        ??????????trigger(toRaw(this),?TriggerOpTypes.SET,?'value')
        ????????}
        ??????}
        ????})

        ????this[ReactiveFlags.IS_READONLY]?=?isReadonly
        ??}

        ??get?value()?{
        ????if?(this._dirty)?{
        ??????//?返回當前值
        ??????//?將變更狀態(tài)變?yōu)?false
        ??????this._value?=?this.effect()
        ??????this._dirty?=?false
        ????}
        ????// track:effect api 的 track 函數(shù),用于追蹤用戶行為,當前則是追蹤用戶的 get 操作
        ????track(toRaw(this),?TrackOpTypes.GET,?'value')
        ????return?this._value
        ??}

        ??set?value(newValue)?{
        ????this._setter(newValue)
        ??}
        }

        computed

        傳入一個 getter 函數(shù),返回一個默認不可手動修改的 ref 對象?;蛘邆魅胍粋€擁有 getset 函數(shù)的對象,創(chuàng)建一個可手動修改的計算狀態(tài)。

        示例如下:

        const?count1?=?ref(1)
        const?plus1?=?computed(()?=>?count1.value?+?1)
        console.log(plus1.value)?//?2
        plus1.value++?//?Write?operation?failed:?computed?value?is?readonly

        const?count2?=?ref(1)
        const?plus2?=?computed({
        ??get:?()?=>?count2.value?+?1,
        ??set:?val?=>?{
        ????count2.value?=?val?-?1
        ??}
        })
        console.log(plus2.value)?//?2
        plus2.value?=?0
        console.log(plus2.value)?//?0

        后記

        如果你喜歡探討技術,或者對本文有任何的意見或建議,非常歡迎加魚頭微信好友一起探討,當然,魚頭也非常希望能跟你一起聊生活,聊愛好,談天說地。魚頭的微信號是:krisChans95 也可以掃碼關注公眾號,訂閱更多精彩內容。


        瀏覽 43
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            精品无码一级毛片免费 | www啊啊啊 | 国产精品电影一区二区 | 小舞一边脱一边摸一边吃胸亲 | 夜夜干夜夜操 | 插B综合网 | 91无码| 亚洲精品乱码久久久久久蜜桃欧美 | 日韩成人无码毛片 | 美女丝袜一区二区三区 |