VueUse
Shared ➜
computedEager
- watchEffect 的第二參數的
flush: sync代表同步調用。 watchEffect一直在檢查todo.length,但因為result是shallowRef,所以只有在!!todo.length的值發生改變時才會讓result感受到變動並更新。
computedWithControl
- source 變動時
computedRef可拿到新的 counter 值,否則都是舊的,若 source 沒有變動也可以透過computedRef.trigger()去強制更新。 dirty負責記錄是否被更新過(true將重新取得 counter 的值)。- customRef 有兩個參數:
track追蹤參數、trigger觸發更新。 - Object.isExtensible() 判斷參數是否可以擴展 → 確認可以新增或修改 key / value。
createEventHook
- on 可以掛載多個 callback function,利用 trigger 觸發更新。
- tryOnScopeDispose() 判斷目前是否在 effect scope 內,是的話就執行
onScopeDispose(),不是的話則什麼都不做。 - onScopeDispose() 在當前的 effect scope 上註冊一個處理 callback function,當相關的 effect scope 停止時會呼叫這個 callback function。
- Component 的 setup 或
scope.run()的 function 裡面就代表是在 effect scope 裡面。
createGlobalState
- 建立一個獨立的 Scope,全域都可以存取同一份,像 Store。
- effect scope 的好處是若需要停止響應性可以直接
scope.stop(),不需要一個一個做註銷(但這裡沒有提供此功能)
createInjectionState
和
createGlobalState不同之處在於創建的狀態是在 Vue 的provide/inject系統中共享的,因此只有在注入到具有相同依賴的範圍內時才會共享。provide/inject可以明確地指定哪些變數是由哪些父層組件提供的,並限制這些變數的作用範圍,可以使程式碼更易於管理和理解,也可以減少不必要的全域變數。provide / inject 和全域共享的差別:
- 使用
provide/inject,子層要變更資料時必須透過父層提供的方法或資料屬性,然後讓父層透過provide把變更後的資料傳遞下去,才能達到資料的共享。 - 使用全域變數,子層可以直接存取或修改全域變數,但因為沒有明確的資料流傳遞,所以可能會出現管理上的問題。
- 使用
composable()可以組合多個響應式物件。在某些情況下,使用 composable 可以達到類似全域共享的效果,但是它們的本質是不同的。
- composable 主要是用於抽象出可重複使用的邏輯單元,這些邏輯單元可以在不同的 Vue 組件中使用,而不需要關注各自的狀態管理。(注重邏輯的抽象和可重複使用性)
- 全域共享主要是用於在整個應用中共享狀態,並且可以在任何組件中存取和修改這些狀態。(注重狀態的共享和可讀寫性)
createSharedComposable
- 和
createGlobalState相似,差別在於createSharedComposable在沒有任何訂閱使用的情況下會做scope.stop()。 再次被使用才會重新創建 effectScope。
extendRef
- 可以對
ref進行擴展,添加額外的 function 或屬性。 - 直接在
ref.value上添加 function,可能會污染ref的原型,進而影響到其他地方的使用,因此,使用extendRef來對ref進行擴展更加地優雅和安全。 unwrap:若值為true,則extendRef函數將會將Ref物件轉換為其值,並將其設置為屬性的值;false的話屬性的值將是Ref物件本身。if (key === 'value') continue: 跳過extend物件中key為'value'的屬性。 因為Ref物件中的值是透過.value存取的,如果直接將extend物件中的value屬性設置為Ref物件的屬性會造成名稱衝突,因此需要跳過value屬性。Object.defineProperty(ref, key, { get, set, enumerable }):
會定義ref物件的key屬性的 getter 和 setter 方法,透過這些方法來操作Ref物件的value屬性(不需要.value就能直接取到值)。Object.defineProperty(ref, key, { value, enumerable }):
如果unwrap被設定為false,則直接將Ref物件賦值給ref物件的key屬性,訪問ref.key回傳的是Ref物件本身(需要.value才能取到值)。
get
unref():將參數轉換為普通的物件。MaybeRef<T>:接受Ref或普通值的參數。
使用MaybeRef<T>作為類型註解的好處是,在接收參數時可以直接傳入普通值或Ref。
isDefined
- 用於檢查變數是否已定義(defined)。
如果變數為null或undefined,該函數將回傳false,否則回傳true。
makeDestructurable
- 將物件和陣列組合起來,使其同時具有物件和陣列的特性,並且能夠進行解構操作。
typeof Symbol !== 'undefined’:確認瀏覽器是否支援 Symbol 這個資料型別。- 在
obj這個物件上,定義一個Symbol.iterator屬性,並指定一個回傳迭代器物件的函式(陣列有此屬性,但物件沒有),當這個物件被迭代時,就會依次回傳arr陣列中的值。 - 當程式碼使用
for...of迴圈來迭代物件時,它會尋找該物件的Symbol.iterator屬性,所以為了讓物件能夠被for...of迴圈正確地迭代,需要為物件加上Symbol.iterator屬性。 - 最後將
obj和arr合併成一個新的物件並回傳。
reactify
- 將普通的函数轉換為具有響應式特性的函數。
這些轉換後的函數可以接受 refs 作為參數,並回傳一個 ComputedRef 物件,可以訪問和監聽該物件的值的變化。 unref:將 Ref 物件轉換為普通物件,如果傳入的參數不是 Ref 物件,則直接回傳該值。toValue:傳入的參數是 function(getter)的話會執行,不是的話會做unref。args.map(i => unrefFn(i)):將所有參數map成普通值。fn.apply(thisArg, [argsArray]):fn是要調用的函數,thisArg是函數執行時的this上下文,而argsArray則是傳遞給函數的參數陣列。computed(() => fn.apply(this, args.map(i => unrefFn(i)))):
將參數做轉為普通物件才能讓原本的fn取到值並正常執行,而因為 computed 內部還是有用到unrefFn(i),對 computed 來說i仍然會被搜集到響應性的依賴,所以當i發生變化時,將會促使 computed 下次被取值時需要重新計算。
reactifyObject
- 如果屬性的值是一個函數,則使用 reactify 函數將其轉換為響應式函數。
Object.getOwnPropertyNames:回傳一個陣列,其中包含物件自身所有屬性的名稱,包括不可列舉的屬性。Object.keys:回傳一個陣列,其中僅包含物件自身的所有可列舉屬性的名稱。
reactiveComputed
- Computed reactive 物件。
回傳的是一個reactive物件,而不是像computed回傳的ref物件。 (不需要.value取值)
reactiveOmit
- 從一個響應式物件中響應式地省略字段。
javascript
import { reactive } from 'vue'
import { reactiveOmit } from '@vueuse/core'
const obj = reactive({
x: 0,
y: 0,
elementX: 0,
elementY: 0,
})
const picked = reactiveOmit(obj, "x", "elementX")javascript
console.log(picked)
// Proxy {}
console.log(JSON.stringify(picked))
// {"y": 0, "elementY": 0}
console.log(picked.y)
// 0
console.log(obj)
// Proxy {x: 0, y: 0, elementX: 0, elementY: 0}html
<div>
{{ picked }}
<!-- { "y": 0, "elementY": 0 } -->
</div>Array.flat([depth]):將一個多維陣列扁平化成新的一維陣列,參數可以指定展開的深度,預設為 1。Object.entries():直接取得所有屬性的 key 和 value,並以 Tuple 的陣列回傳。Object.fromEntries():將 key-value 的 Tuple 陣列轉換為物件。toRefs(reactiveObj):會將reactiveObj轉換為一個物件,而物件內所有value轉為ref。ref是響應式的,可以讓reactiveComputed在需要時更新新物件的值。
reactivePick
- 從一個響應式物件中響應式地選擇字段。
UnwrapRef<T>:對 Ref 型別做分解。 如果 T 是 Ref 型別,則 UnwrapRef 型別為 ref.value 的型別。 如果 T 不是 Ref 型別,則 UnwrapRef 型別為 T。- toRef():可用於將一個響應式物件(ref)的某個屬性轉換為一個獨立的響應式物件。
- 基本上與
reactiveOmit相似,只是反過來。
refAutoReset
- 建立一個可透過參數指定時間(ms),並在時間到後重置為默認值的 ref。
refDebounced
- (Debounce)延遲更新 ref 值,在參數指定時間過後 ref 值的更新才會執行。
- 利用 useDebounceFn() 將更新值的動作延遲到指定時間結束後。
refDefault
- 給 ref 定義預設值(當
ref.value = undefined | null時會get()會取得預設值)。 - 回傳
computed,將get()內部做處理判斷。
refThrottled
- (Throttle)限制 ref 值的更新次數。
leading:指定呼叫在 throttle 開始前。trailing:指定呼叫在 throttle 結束後。
refWithControl
- 利用
extendRef提供了兩個額外的函數get和set,以更好地控制何時 track / trigger 響應性。 - 不會觸發響應性的 getter
javascript
const foo = refWithControl('foo')
foo.get(false)
foo.untrackedGet()
foo.peek()- 不會觸發響應性的 setter
javascript
const foo = refWithControl('foo')
foo.set('bar', false)
foo.silentSet('bar')
foo.lay('bar')onBeforeChange():可以控制是否接受新的值。(拒絕就return false)
javascript
const num = refWithControl(0, {
onBeforeChange(value, oldValue) {
if (Math.abs(value - oldValue) > 5)
return false
},
})onChanged():與 Vue 的watch相似,但它的同步開銷更少。
javascript
const num = refWithControl(0, {
onChanged(value, oldValue) {
console.log(value)
},
})options.onBeforeChange?.(value, old)先判斷onBeforeChange是否為undefined | null,若不是再進一步調用函數(和參數之間要加.)。
resolveRef
- 將 value、ref 或 getter 規範化為
ref或computed。 - 判斷傳進的參數是否為 function,是的話回傳 computed,否則回傳 ref。
toValue
- 原本名稱是
resolveUnref。 - 取得 value、ref、getter 的值。
- 判斷傳進的參數是否為 function(Getter),是的話回傳執行的結果,否則回傳
unref()的結果。
set
ref.value = x的簡寫。
javascript
set(ref, x) // ref
set(obj, key, x) // object- 透過參數數量判斷要更新的值是 ref 或是 object。
syncRef
- 可以實現雙向引用(two-way refs)的同步,將兩個
Ref物件之間的變更同步,也可以透過參數更改成單向同步。 - 回傳值是可以取消監聽器的函式。
- 使用
watch而不是computed的好處是有更多客製化的選項,包含:flush、deep、immediate。
syncRefs
- 讓 target ref(多個可寫成陣列)的值與 source ref 的值保持同步。
- target 在傳入的時候若不是陣列(單個)會先另外放在陣列內,透過 forEach 將 source 的新值去賦值給每項
target.value。 - 回傳值是可以取消監聽器的函式。
toReactive
- 將 ref 轉換為 reactive,還可以創建一個可替換的 reactive 物件。
toRefs
- 可以將普通或具響應性的物件、陣列等的最外層都轉換成 ref 以方便解構使用。
- 若傳入的參數不是 ref(普通的物件、陣列或 reactive),直接回傳 toRef() 的結果。
- 若傳入的參數是 ref,則不管是物件或是陣列都將最外層的每一項做
customRef()。 - 每一項的
get()和set()都是從 objectRef 去取得或是藉由重新賦值去觸發 objectRef 的響應的。(也因此不需手動添加track()和trigger())
tryOnBeforeMount
- 如果在 component 的生命週期內,呼叫
onBeforeMount;不是則單純執行參數 function。 onBeforeMount:負責處理在 component 初次渲染之前需要完成的操作。
調用的時機點為 component 已經完成設置其響應性狀態,但還沒有創建任何 DOM 節點,即將第一次地執行其 DOM 渲染效果。
tryOnBeforeUnmount
- 如果在 component 的生命週期內,呼叫
onBeforeUnmount;不是則什麼都不做。 onBeforeUnmount:調用時機為當 component instance 即將被卸載時(仍可使用)。
tryOnMounted
- 如果在 component 的生命週期內,呼叫
onMounted;不是則單純執行參數 function。 onMounted:調用時機為 component 被掛載後。
掛載的條件為
- 所有同步子元件都已經被掛載(不包括異步元件或在
<Suspense>樹中的元件)。 - 自身的 DOM 樹已經被創建並插入到父容器中。(如果應用程式的根容器也在 document 中,則只保證元件的 DOM 樹在 document 中。)
tryOnScopeDispose
- 如果在 effect scope 內就執行
onScopeDispose(),不是的話則什麼都不做。 onScopeDispose:註冊一個 dispose callback 在當前的 effect scope 上,調用時機為相關的 effect scope 被停止時。
tryOnUnmounted
- 如果在 component 的生命週期內就執行
onUnmounted(),不是的話則什麼都不做。 onUnmounted:調用時機為 component 被卸載後。
卸載的條件為
- 所有子元件都被卸載。
- 所有相關的 reactive effects(渲染效果、在 setup 中所註冊的 computed 或 watchers)都被停止。
until
- 一次性的觀察變化(Promise)。
- function
toBe的[v1, v2]指的是r和value。
useArrayEvery
- 響應性的
Array.every。 Array.every的型別是
typescript
Array<T>.every(
predicate: (element: T, index: number, array: T[]) => unknown,
thisArg?: any
): boolean所以傳入 useArrayEvery 的 fn 型別是 Array.every 的 predicate 型別。
- 在傳入
fn參數時,是 callback function,不限制有幾項參數。 i拿到的值為第一項(element)。
useArrayFilter
- 響應性的
Array.filter。
useArrayFind
- 響應性的
Array.find。
useArrayFindIndex
- 響應性的
Array.findIndex。
useArrayFindLast
- 響應性的
Array.findLast。 !Array.prototype.findLast:判斷版本是否有支援findLast。
useArrayJoin
- 響應性的
Array.join
useArrayMap
- 響應性的
Array.map
useArrayReduce
- 響應式的
Array.reduce。 MaybeRefOrGetter<MaybeRefOrGetter<T>[]>代表MaybeRefOrGetter的陣列裡每一項都是MaybeRefOrGetter。type MaybeRefOrGetter<T> = MaybeReadonlyRef<T> | MaybeRef<T>- Type
UseArrayReducer是Array.reduce第一個參數的型別:
typescript
(
previousValue: PV,
currentValue: CV,
currentIndex: number,
// array: T[]
) => RuseArraySome
- 響應式的
Array.some。 - 如果直接寫
some(fn)就不能將每次迭代的element先做toValue了。 fn(toValue(element), index, array)應該會拿到原本該回傳的 boolean。
useArrayUnique
- 響應式的陣列且內部元素不重複。
- 若為物件陣列可以自定義判別式。
useCounter
- 附有功能的基本計數器。
useDateFormat
- 根據傳遞的令牌字符串(e.g.
YYYY-MM-DD)獲取格式化的日期。 []包起來的字串不會被解析成日期(因為:\[([^\]]+)])
可以拆成這樣看: \[ ( [^ \] ] + ) ]- 利用正則匹配和 replace 將字串轉換成日期。
!/Z$/i.test(date)的用意是排除不需要做時區轉換的字串。(最後面如果是Z就代表UTC +0時區。)date.match(REGEX_PARSE)將字串透過正則匹配回傳拆分完的陣列。
javascript
const REGEX_PARSE = /^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/
const date = '2000/11/23 15:23:38:34'.match(REGEX_PARSE)
// [ "2000/11/23 15:23:38:34", "2000", "11", "23", "15", "23", "38", "34" ]str.substring(indexStart[, indexEnd])回傳一個字串從indexStart到indexEnd前一項,或最後一項。
useDebounceFn
- (Debounce)延遲執行一個函數。
maxWait:延遲的最大時間(ms),若都沒有達成調用則時限到必定調用一次。rejectOnCancel:設置選項rejectOnCancel: true才能catch到 Promise 被拒絕。(決定lastRejector()是執行resolve還是reject) 預設情況函數若被取消,Promise 不會被拒絕。createFilterWrapper()會回傳一個回傳 Promise 的 function 。debounceFilter():
useInterval
- 響應性計數器(根據時間間隔增加)。
controls: exposeControls = false將controls取別名exposeControls,預設為false。
useIntervalFn
- 具控制功能的
setInterval封裝程式。 - isClient:
typeof window !== 'undefined'
useLastChanged
- 記錄最後一次更改的時間戳。
- 內部以
watch實作。
useThrottleFn
- 限制函數的執行。 對於限制處理程序在調整大小和滾動等事件上的執行速度特別有用。
trailing:若為true,將會在ms時間結束後再次調用fn。leading:若為true,則在ms時間結束前一刻調用fn。rejectOnCancel:若為true,如果已取消的話將拒絕最後一次呼叫。
useTimeout
- 控制在給定的時間後更新 value。
- 使用到
useTimeoutFn,並回傳ready表示是否完成更新。
useTimeoutFn
- 指定
cb在interval後再執行,計時時間內isPending = true。
useToNumber
- 響應性地轉換字串 ref 為數字。
useToString
- 響應性地使用
${ }將 ref 的 value 轉換成字串。
useToggle
- Boolean 切換器。
- 若參數傳進 ref,會回傳 toggle function。
- 為了預防
$event擔任第一參數蓋掉 value,寫成useToggle()以保證無參數傳入。 vue-demi:為 Vue 2 和 Vue 3 所創建的通用函式庫。isRef:檢查參數值是否為 ref 物件。
watchArray
- watch 陣列的添加和刪除。
- 類似 watch,但會將新增和移除的元素提供給 callback function。如果陣列透過
push、splice等方式作更新,將會傳遞{ deep: true }。 type WatchSource<T = any> = Ref<T> | ComputedRef<T> | (() => T)oldListRemains:用來記錄陣列值的差異,false表示這項值並不是新舊陣列都存在(可能是新增或是刪除了),true則代表新舊陣列皆有(沒有變動)。found:用來記錄是否為新增的值。false代表舊陣列沒有這項值(需要新增到added陣列和oldList陣列內),true則代表有(不需改動)。
watchAtMost
- 若觸發次數超過
count,則會註銷 watch。 watchWithFilter()回傳的stop是註銷 watch 的函數。
watchDebounced
- 額外提供
debounce和maxWait的watch。 - 基本就是使用
watchWithFilter在參數eventFilter傳入debounceFilter。
watchIgnorable
- 回傳
ignoreUpdates(updater)和ignorePrevAsyncUpdates()以忽略對 source 的特定更新。 ignoreUpdates(updater):參數updater(callback)對於 source 進行改動時不會觸發 watch。ignorePrevAsyncUpdates():只適用於非同步刷新pre和post。 如果使用了flush: 'sync',則ignorePrevAsyncUpdates()不會起作用,因為每次更新 source 後,watch 將立即觸發。- 在
flush為sync的情況下,ignorePrevAsyncUpdates = () => {}。 - source 每次更新時,
ignoreCounter和syncCounter會先歸零,接著syncCounter++ - 只有使用到
ignoreUpdates(updater)或ignorePrevAsyncUpdates()時ignoreCounter才會> 0。
watchImmediate
watch的{ immediate: true }版本。
watchOnce
- 只觸發一次的
watch。 - 在執行指定函式時,利用
nextTick(() => stop())去執行watch所回傳的停止函式。
watchPausable
- 可以藉由回傳額外的
pause()和resume()函數來控制。 - 利用
watchWithFilter再包一層判斷isActive為true才執行原函式的動作。 pause()將isActive設為false,resume()將isActive設為True。
watchThrottled
throttle:在間隔期間內只允許調用一次。trailing:在間隔期間內觸發,若為true則會等待間隔時間結束後調用。若為false則就算間隔時間結束也不會調用。leading:若為true則在觸發時立刻調用,若為false則在間隔時間結束時才調用。- 基本就是使用
watchWithFilter在參數eventFilter傳入throttleFilter。
watchTriggerable
- 提供在響應式物件沒有變動時也可以手動觸發 watch 的函式。
onCleanup:會在下一次 watch 的 callback 函式執行前執行參數(也是 callback),可用來改變上一次 watch 的 callback 函式作用域內的變數。
watchWithFilter
- 回傳 watch,callback function 使用到
createFilterWrapper()(可以多包一層需要的執行條件)。
whenever
- 參數格式與 watch 相同,差別在於是監測 Boolean 的響應式物件,當物件為
true時才執行 callback。