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