vue3 文檔梳理快速入門
一、setup
組合式 API:
setup選項應(yīng)該為一個函數(shù)setup選項函數(shù)接受兩個參數(shù):props和contextsetup選項函數(shù)需要返回要暴露給組件的內(nèi)容setup需要使用return返回,才能給組件使用,包含數(shù)據(jù)和方法
1. setup 函數(shù)中的第一個參數(shù) —— props
setup 函數(shù)中的 props 是響應(yīng)式的,當傳入新的 prop 時,它將被更新
export default {
props: {
title: String
},
setup(props) {
console.log(props.title)
}
}
但是,因為 props 是響應(yīng)式的,你不能使用 ES6 解構(gòu),因為它會消除 prop 的響應(yīng)性。
如果需要解構(gòu) prop,可以通過使用 setup 函數(shù)中的 toRefs 來安全地完成此操作。
import { toRefs } from 'vue'
setup(props) {
const { title } = toRefs(props)
console.log(title.value)
}
2. contextcontext
setup函數(shù)中的第二個參數(shù) ——contextcontext上下文是一個普通的 JavaScript 對象,它暴露三個組件的 property
xport default {
setup(props, context) {
// Attribute (非響應(yīng)式對象)
console.log(context.attrs)
// 插槽 (非響應(yīng)式對象)
console.log(context.slots)
// 觸發(fā)事件 (方法)
console.log(context.emit)
}
}
context 是一個普通的 JavaScript 對象,也就是說,它不是響應(yīng)式的,這意味著你可以安全地對 context 使用 ES6 解構(gòu)
export default {
setup(props, { attrs, slots, emit }) {
...
}
}
二、setup 函數(shù)的返回值
1.setup 函數(shù)的返回值 —— 對象
如果 setup 返回一個對象,則可以在組件的模板中像傳遞給 setup 的 props property 一樣訪問該對象的 property:
<template>
<!-- 模板中使用會被自動解開,所以不需要 .value -->
<div>{{ readersNumber }} {{ book.title }}</div>
</template>
<script>
import { ref, reactive } from 'vue'
export default {
setup() {
const readersNumber = ref(0)
const book = reactive({ title: 'Vue 3 Guide' })
// expose to template
return {
readersNumber,
book
}
}
}
</script>
注意:從 setup 返回的 refs 在模板中訪問時是被自動解開的,因此不應(yīng)在模板中使用 .value
三、響應(yīng)式系統(tǒng) API
1. reactive
reactive() 接收一個普通對象然后返回該普通對象的響應(yīng)式代理。等同于 2.x 的 Vue.observable()
const obj = reactive({ count: 0 })
響應(yīng)式轉(zhuǎn)換是“深層的”:會影響對象內(nèi)部所有嵌套的屬性?;?ES2015 的 Proxy 實現(xiàn),返回的代理對象不等于原始對象。建議僅使用代理對象而避免依賴原始對象。
<template>
<div id="app">{ state.count }</div>
</template>
<script>
import { reactive } from 'vue'
export default {
setup() {
// state 現(xiàn)在是一個響應(yīng)式的狀態(tài)
const state = reactive({
count: 0,
})
}
}
</script>
2. ref
接受一個參數(shù)值并返回一個響應(yīng)式且可改變的 ref 對象。ref 對象擁有一個指向內(nèi)部值的單一屬性 .value。
const count = ref(0) console.log(count.value) // 0 count.value++ console.log(count.value) // 1
如果傳入 ref 的是一個對象,將調(diào)用 reactive 方法進行深層響應(yīng)轉(zhuǎn)換。
模板中訪問:
當 ref 作為渲染上下文的屬性返回(即在setup() 返回的對象中)并在模板中使用時,它會自動解套,無需在模板內(nèi)額外書寫 .value:
<template>
<div>{{ count }}</div>
</template>
<script>
export default {
setup() {
return {
count: ref(0),
}
},
}
</script>
作為響應(yīng)式對象的屬性訪問:
當 ref 作為 reactive 對象的 property 被訪問或修改時,也將自動解套 value 值,其行為類似普通屬性:
const count = ref(0)
const state = reactive({
count,
})
console.log(state.count) // 0
state.count = 1
console.log(count.value) // 1
注意:如果將一個新的 ref 分配給現(xiàn)有的 ref, 將替換舊的 ref:
const otherCount = ref(2) state.count = otherCount console.log(state.count) // 2 console.log(count.value) // 1
注意:當嵌套在 reactive Object 中時,ref 才會解套。從 Array 或者 Map 等原生集合類中訪問 ref 時,不會自動解套:
const arr = reactive([ref(0)])
// 這里需要 .value
console.log(arr[0].value)
const map = reactive(new Map([['foo', ref(0)]]))
// 這里需要 .value
console.log(map.get('foo').value)
類型定義:
interface Ref<T> {
value: T
}
function ref<T>(value: T): Ref<T>
有時我們可能需要為 ref 做一個較為復雜的類型標注。我們可以通過在調(diào)用 ref 時傳遞泛型參數(shù)來覆蓋默認推導:
const foo = ref<string | number>('foo') // foo 的類型: Ref<string | number>
foo.value = 123 // 能夠通過!
3. computed
使用響應(yīng)式 computed API 有兩種方式:
(1)傳入一個 getter 函數(shù),返回一個默認不可手動修改的 ref 對象。
const count = ref(1) const plusOne = computed(() => count.value + 1) console.log(plusOne.value) // 2 plusOne.value++ // 錯誤!
(2)傳入一個擁有 get 和 set 函數(shù)的對象,創(chuàng)建一個可手動修改的計算狀態(tài)。
const count = ref(1)
const plusOne = computed({
get: () => count.value + 1,
set: (val) => {
count.value = val - 1
},
})
plusOne.value = 1
console.log(count.value) // 0
類型定義:
// 只讀的
function computed<T>(getter: () => T): Readonly<Ref<Readonly<T>>>
// 可更改的
function computed<T>(options: {
get: () => T
set: (value: T) => void
}): Ref<T>
4. readonly
傳入一個對象(響應(yīng)式或普通)或 ref,返回一個原始對象的只讀代理。一個只讀的代理是“深層的”,對象內(nèi)部任何嵌套的屬性也都是只讀的。
const original = reactive({ count: 0 })
const copy = readonly(original)
watchEffect(() => {
// 依賴追蹤
console.log(copy.count)
})
// original 上的修改會觸發(fā) copy 上的偵聽
original.count++
// 無法修改 copy 并會被警告
copy.count++ // warning!
5. watchEffect
立即執(zhí)行傳入的一個函數(shù),并響應(yīng)式追蹤其依賴,并在其依賴變更時重新運行該函數(shù)。
const count = ref(0)
watchEffect(() => console.log(count.value))
// -> 打印出 0
setTimeout(() => {
count.value++
// -> 打印出 1
}, 100)
5.1 停止偵聽
當 watchEffect 在組件的 setup() 函數(shù)或生命周期鉤子被調(diào)用時, 偵聽器會被鏈接到該組件的生命周期,并在組件卸載時自動停止。
在一些情況下,也可以顯式調(diào)用返回值以停止偵聽:
const stop = watchEffect(() => {
/* ... */
})
// 之后
stop()
5.2 清除副作用
有時副作用函數(shù)會執(zhí)行一些異步的副作用, 這些響應(yīng)需要在其失效時清除(即完成之前狀態(tài)已改變了)。所以偵聽副作用傳入的函數(shù)可以接收一個 onInvalidate 函數(shù)作入?yún)? 用來注冊清理失效時的回調(diào)。當以下情況發(fā)生時,這個失效回調(diào)會被觸發(fā):
- 副作用即將重新執(zhí)行時
- 偵聽器被停止 (如果在 setup() 或 生命周期鉤子函數(shù)中使用了 watchEffect, 則在卸載組件時)
watchEffect((onInvalidate) => {
const token = performAsyncOperation(id.value)
onInvalidate(() => {
// id 改變時 或 停止偵聽時
// 取消之前的異步操作
token.cancel()
})
})
我們之所以是通過傳入一個函數(shù)去注冊失效回調(diào),而不是從回調(diào)返回它(如 React useEffect 中的方式),是因為返回值對于異步錯誤處理很重要。
在執(zhí)行數(shù)據(jù)請求時,副作用函數(shù)往往是一個異步函數(shù):
const data = ref(null)
watchEffect(async () => {
data.value = await fetchData(props.id)
})
我們知道異步函數(shù)都會隱式地返回一個 Promise,但是清理函數(shù)必須要在 Promise 被 resolve 之前被注冊。另外,Vue 依賴這個返回的 Promise 來自動處理 Promise 鏈上的潛在錯誤。
5.3 副作用刷新時機
Vue 的響應(yīng)式系統(tǒng)會緩存副作用函數(shù),并異步地刷新它們,這樣可以避免同一個 tick 中多個狀態(tài)改變導致的不必要的重復調(diào)用。在核心的具體實現(xiàn)中, 組件的更新函數(shù)也是一個被偵聽的副作用。當一個用戶定義的副作用函數(shù)進入隊列時, 會在所有的組件更新后執(zhí)行:
<template>
<div>{{ count }}</div>
</template>
<script>
export default {
setup() {
const count = ref(0)
watchEffect(() => {
console.log(count.value)
})
return {
count,
}
},
}
</script>
在這個例子中:
count 會在初始運行時同步打印出來
更改 count 時,將在組件更新后執(zhí)行副作用。
請注意:初始化運行是在組件 mounted 之前執(zhí)行的。因此,如果你希望在編寫副作用函數(shù)時訪問 DOM(或模板 ref),請在 onMounted 鉤子中進行:
onMounted(() => {
watchEffect(() => {
// 在這里可以訪問到 DOM 或者 template refs
})
})
如果副作用需要同步或在組件更新之前重新運行,我們可以傳遞一個擁有 flush 屬性的對象作為選項(默認為 'post'):
// 同步運行
watchEffect(
() => {
/* ... */
},
{
flush: 'sync',
}
)
// 組件更新前執(zhí)行
watchEffect(
() => {
/* ... */
},
{
flush: 'pre',
}
)
5.4 偵聽器調(diào)試
onTrack 和 onTrigger 選項可用于調(diào)試一個偵聽器的行為。
- 當一個
reactive對象屬性或一個ref作為依賴被追蹤時,將調(diào)用onTrack - 依賴項變更導致副作用被觸發(fā)時,將調(diào)用
onTrigger
這兩個回調(diào)都將接收到一個包含有關(guān)所依賴項信息的調(diào)試器事件。建議在以下回調(diào)中編寫 debugger 語句來檢查依賴關(guān)系:
watchEffect(
() => {
/* 副作用的內(nèi)容 */
},
{
onTrigger(e) {
debugger
},
}
)
onTrack 和 onTrigger 僅在開發(fā)模式下生效。
類型定義:
function watchEffect(
effect: (onInvalidate: InvalidateCbRegistrator) => void,
options?: WatchEffectOptions
): StopHandle
interface WatchEffectOptions {
flush?: 'pre' | 'post' | 'sync'
onTrack?: (event: DebuggerEvent) => void
onTrigger?: (event: DebuggerEvent) => void
}
interface DebuggerEvent {
effect: ReactiveEffect
target: any
type: OperationTypes
key: string | symbol | undefined
}
type InvalidateCbRegistrator = (invalidate: () => void) => void
type StopHandle = () => void
6. watch
watch API 完全等效于 2.x this.$watch (以及 watch 中相應(yīng)的選項)。watch 需要偵聽特定的數(shù)據(jù)源,并在回調(diào)函數(shù)中執(zhí)行副作用。默認情況是懶執(zhí)行的,也就是說僅在偵聽的源變更時才執(zhí)行回調(diào)。
- 對比
watchEffect,watch允許我們:
- 懶執(zhí)行副作用;
- 更明確哪些狀態(tài)的改變會觸發(fā)偵聽器重新運行副作用;
- 訪問偵聽狀態(tài)變化前后的值。
- 偵聽單個數(shù)據(jù)源
- 偵聽器的數(shù)據(jù)源可以是一個擁有返回值的 getter 函數(shù),也可以是 ref:
// 偵聽一個 getter
const state = reactive({ count: 0 })
watch(
() => state.count,
(count, prevCount) => {
/* ... */
}
)
// 直接偵聽一個 ref
const count = ref(0)
watch(count, (count, prevCount) => {
/* ... */
})
6.1 偵聽多個數(shù)據(jù)源
watcher 也可以使用數(shù)組來同時偵聽多個源:
watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => {
/* ... */
})
6.2 與 watchEffect 共享的行為
watch 和 watchEffect 在停止偵聽, 清除副作用 (相應(yīng)地 onInvalidate 會作為回調(diào)的第三個參數(shù)傳入),副作用刷新時機 和 偵聽器調(diào)試 等方面行為一致.
類型定義:
// 偵聽單數(shù)據(jù)源
function watch<T>(
source: WatcherSource<T>,
callback: (
value: T,
oldValue: T,
onInvalidate: InvalidateCbRegistrator
) => void,
options?: WatchOptions
): StopHandle
// 偵聽多數(shù)據(jù)源
function watch<T extends WatcherSource<unknown>[]>(
sources: T
callback: (
values: MapSources<T>,
oldValues: MapSources<T>,
onInvalidate: InvalidateCbRegistrator
) => void,
options? : WatchOptions
): StopHandle
type WatcherSource<T> = Ref<T> | (() => T)
type MapSources<T> = {
[K in keyof T]: T[K] extends WatcherSource<infer V> ? V : never
}
// 共有的屬性 請查看 `watchEffect` 的類型定義
interface WatchOptions extends WatchEffectOptions {
immediate?: boolean // default: false
deep?: boolean
}
到此這篇關(guān)于vue3 文檔梳理快速入門的文章就介紹到這了,更多相關(guān)vue3 文檔梳理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
從vue基礎(chǔ)開始創(chuàng)建一個簡單的增刪改查的實例代碼(推薦)
這篇文章主要介紹了從vue基礎(chǔ)開始創(chuàng)建一個簡單的增刪改查的實例代碼,需要的朋友參考下2018-02-02
vue前端開發(fā)輔助函數(shù)狀態(tài)管理詳解示例
vue的應(yīng)用狀態(tài)管理提供了mapState、mapGetters、mapMutations、mapActions四個輔助函數(shù),所謂的輔助函數(shù)分別對State、Getters、Mutations、Actions在完成狀態(tài)的使用進行簡化2021-10-10
vue elementUI實現(xiàn)自定義正則規(guī)則驗證
本文主要介紹了vue elementUI實現(xiàn)自定義正則規(guī)則驗證,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-03-03
vue3+vite使用環(huán)境變量.env的一些配置情況詳細說明
開發(fā)中經(jīng)常會使用環(huán)境變量,Vite相比于Webpack也有一定的變化,下面這篇文章主要給大家介紹了關(guān)于vue3+vite使用環(huán)境變量.env的一些配置情況說明的相關(guān)資料,需要的朋友可以參考下2022-12-12
vue.js配合$.post從后臺獲取數(shù)據(jù)簡單demo分享
今天小編就為大家?guī)硪黄獀ue.js配合$.post從后臺獲取數(shù)據(jù)簡單demo分享,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-08-08
詳解Jest結(jié)合Vue-test-utils使用的初步實踐
這篇文章主要介紹了詳解Jest結(jié)合Vue-test-utils使用的初步實踐,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-06-06

