<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          讓Composition API 存在于 Vue3.0 項目以外

          共 7365字,需瀏覽 15分鐘

           ·

          2020-10-13 19:17

          • 作者:陳大魚頭
          • 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?已經(jīng)是一個?Proxy?時,直接返回
          ??????//?例外情況:在 Proxy 里調(diào)用 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ù)類型生成對應(yīng)的?Proxy?對象,以及添加對應(yīng)的處理器
          ????const?proxy?=?new?Proxy(
          ??????target,
          ??????targetType?===?TargetType.COLLECTION???collectionHandlers?:?baseHandlers
          ????)
          ????proxyMap.set(target,?proxy)
          ????return?proxy
          }

          reactive

          接收一個普通對象然后返回該普通對象的響應(yīng)式代理。等同于 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)建淺層的響應(yīng)式代理,不會對“屬性的屬性”做深層次、遞歸響應(yī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í)行回調(diào)
          ??options?=?{
          ????lazy,?//?是否執(zhí)行用戶函數(shù)
          ????scheduler,?//?收集數(shù)據(jù)記錄
          ????onTrack,?//?追蹤用戶數(shù)據(jù)的回調(diào)
          ????onTrigger,?//?追蹤變更記錄
          ????onStop,?//?停止執(zhí)行
          ????allowRecurse?//?是否允許遞歸
          ??}
          )?
          {
          ????const?effect?=?function?reactiveEffect()?{
          ??????if?(!effectStack.includes(effect))?{
          ????????cleanup(effect)?//?清空?effect
          ????????try?{
          ??????????enableTracking()?//?往追蹤用戶數(shù)據(jù)的棧內(nèi)添加當前?effect
          ??????????effectStack.push(effect)?//?往?effect?棧內(nèi)添加?effect
          ??????????activeEffect?=?effect?//?將活動?effect?變成當前?effect
          ??????????return?fn()?//?執(zhí)行回調(diào)
          ????????}?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ù)轉(zhuǎn)換為 reactive 對象
          ????this._value?=?_shallow???_rawValue?:?convert(_rawValue)
          ??}

          ??get?value()?{
          ????//?用于追蹤用戶輸入的值變化
          ????// track:effect api 的 track 函數(shù),用于追蹤用戶行為,當前則是追蹤用戶的 get 操作
          ????// toRaw:effect api 的 toRaw 函數(shù),將 this 轉(zhuǎn)化為用戶輸入值
          ????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ù)值并返回一個響應(yīng)式且可改變的 ref 對象。ref 對象擁有一個指向內(nèi)部值的單一屬性 .value。如果傳入 ref 的是一個對象,將調(diào)用 reactive 方法進行深層響應(yīng)轉(zhuǎn)換。

          示例如下:

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

          shallowRef

          創(chuàng)建一個 ref ,將會追蹤它的 .value 更改操作,但是并不會對變更后的 .value 做響應(yīng)式代理轉(zhuǎn)換(即變更不會調(diào)用 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ā)響應(yīng),接受一個工廠函數(shù),兩個參數(shù)分別是用于追蹤的 track 與用于觸發(fā)響應(yīng)的 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

          ??看完三件事

          如果你覺得這篇內(nèi)容對你挺有啟發(fā),我想邀請你幫我三個小忙:

          1. 點贊,讓更多的人也能看到介紹內(nèi)容(收藏不點贊,都是耍流氓-_-)
          2. 關(guān)注公眾號“前端勸退師”,不定期分享原創(chuàng)知識。
          3. 也看看其他文章

          勸退師個人微信:huab119

          也可以來我的GitHub博客里拿所有文章的源文件:

          前端勸退指南:https://github.com/roger-hiro/BlogFN一起玩耍呀


          bc2db08a4147590819bdc015271373ae.webp


          瀏覽 35
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

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

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  99热都是精品 | 天天干视频 | 免费一级A片毛一女多男 | 国产欧美韩国在线观看 | 婷婷五月天婷婷五月天婷婷五月天色 |