生活随笔
收集整理的這篇文章主要介紹了
Composition API 使用
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- Composition API 常用部分
- 1. setup
- 2. ref
- 3. reactive
- 4. 比較Vue2與Vue3的響應式(重要)
- 5. setup細節
- 6. reactive和ref-的細節問題
- 7. 計算屬性與監視
- 8. 聲明周期對比
- 9. 自定義hook函數
- 10. toRefs
- 11. ref獲取元素
- Composition API 其他部分
- 1. shallowReactive 與 shallowRef
- 2. readonly 與 shallowReadonly
- 3. toRaw 與 markRaw
- 4. toRef
- 5. customRef
- 6. provide 與 inject
- 7. 響應式數據的判斷
- Composition API vs Option API
- 1. 使用Option API
- 2. 使用Compisition API
Composition API 常用部分
1. setup
- 新的option,所有的組合API函數都在此使用,只在初始化時執行一次
- 函數如果返回對象,對象中的屬性或方法,模板中可以直接使用
2. ref
- 作用: 定義一個數據的響應式
- 語法: const xxx = ref(initValue):
- 創建一個包含響應式數據的引用(reference)對象
- js中操作數據: xxx.value
- 模板中操作數據: 不需要.value
- 一般用來定義一個基本類型的響應式數據
- 返回的 count 是 Ref類型
<template
><h2
>{{count
}}</h2
><hr
><button @click
="update">更新
</button
>
</template
><script
>
import {ref
} from 'vue'
export default {setup () {const count
= ref(1)console
.log(count
)function update () {count
.value
= count
.value
+ 1}return {count
,update
}}
}
</script
>
3. reactive
- 作用: 定義多個數據的響應式
- const proxy = reactive(obj): 接收一個普通對象然后返回該普通對象的響應式代理器對象
- 返回的state對象是 Proxy類型
- 響應式轉換是“深層的”:會影響對象內部所有嵌套的屬性
- 內部基于 ES6 的 Proxy 實現,通過代理對象操作源對象內部數據都是響應式的
<template
><h2
>name
: {{state
.name
}}</h2
><h2
>age
: {{state
.age
}}</h2
><h2
>wife
: {{state
.wife
}}</h2
><hr
><button @click
="update">更新
</button
>
</template
><script
>
import {reactive
,
} from 'vue'
export default {setup () {const state
= reactive({name
: 'tom',age
: 25,wife
: {name
: 'marry',age
: 22},})console
.log(state
, state
.wife
)const update = () => {state
.name
+= '--'state
.age
+= 1state
.wife
.name
+= '++'state
.wife
.age
+= 2}return {state
,update
,}}
}
</script
>
4. 比較Vue2與Vue3的響應式(重要)
vue2的響應式
- 核心:
- 對象: 通過defineProperty對對象的已有屬性值的讀取和修改進行劫持(監視/攔截)
- 數組: 通過重寫數組更新數組一系列更新元素的方法來實現元素修改的劫持
Object
.defineProperty(data
, 'count', {get () {}, set () {}
})
- 問題
- 對象直接新添加的屬性或刪除已有屬性, 界面不會自動更新
- 直接通過下標替換元素或更新length, 界面不會自動更新 arr[1] = {}
vue3的響應式
- 核心:
- 通過Proxy(代理): 攔截對data任意屬性的任意(13種)操作, 包括屬性值的讀寫, 屬性的添加, 屬性的刪除等…
- 通過 Reflect(反射): 動態對被代理對象的相應屬性進行特定的操作
- 文檔:
new Proxy(data
, {get (target
, prop
) {return Reflect
.get(target
, prop
)},set (target
, prop
, value
) {return Reflect
.set(target
, prop
, value
)},deleteProperty (target
, prop
) {return Reflect
.deleteProperty(target
, prop
)}
})proxy
.name
= 'tom'
<!DOCTYPE html
>
<html lang
="en">
<head
><meta charset
="UTF-8"><meta name
="viewport" content
="width=device-width, initial-scale=1.0"><title
>Proxy 與 Reflect
</title
>
</head
>
<body
><script
>const user
= {name
: "John",age
: 12};const proxyUser
= new Proxy(user
, {get(target
, prop
) {console
.log('劫持get()', prop
)return Reflect
.get(target
, prop
)},set(target
, prop
, val
) {console
.log('劫持set()', prop
, val
)return Reflect
.set(target
, prop
, val
); },deleteProperty (target
, prop
) {console
.log('劫持delete屬性', prop
)return Reflect
.deleteProperty(target
, prop
)}});console
.log(proxyUser
===user
)console
.log(proxyUser
.name
, proxyUser
.age
)proxyUser
.name
= 'bob'proxyUser
.age
= 13console
.log(user
)proxyUser
.sex
= '男'console
.log(user
)delete proxyUser
.sexconsole
.log(user
)</script
>
</body
>
</html
>
5. setup細節
- setup執行的時機
- 在beforeCreate之前執行(一次), 此時組件對象還沒有創建
- this是undefined, 不能通過this來訪問data/computed/methods/props
- 其實所有的composition API相關回調函數中也都不可以
- setup的返回值
- 一般都返回一個對象: 為模板提供數據, 也就是模板中可以直接使用此對象中的所有屬性/方法
- 返回對象中的屬性會與data函數返回對象的屬性合并成為組件對象的屬性
- 返回對象中的方法會與methods中的方法合并成功組件對象的方法
- 如果有重名,setup優先
- 注意:
- 一般不要混合使用:methods中可以訪問setup提供的屬性和方法,但在setup方法中不能訪問data和methods
- setup不能是一個async函數:因為返回值不再是return的對象,而是promise,模板看不到return對象中的屬性數據
- setup的參數
- setup(props, context) / setup(props, {attrs, slots, emit})
- props: 包含props配置聲明且傳入了的所有屬性的對象
- attrs: 包含沒有在props配置中聲明的屬性的對象, 相當于 this.$attrs
- slots: 包含所有傳入的插槽內容的對象, 相當于 this.$slots
- emit: 用來分發自定義事件的函數, 相當于 this.$emit
<template
><h2
>App
</h2
><p
>msg
: {{msg
}}</p
><button @click
="fn('--')">更新
</button
><child
:msg
="msg" msg2
="cba" @fn
="fn"/>
</template
><script lang
="ts">
import {reactive
,ref
,
} from 'vue'
import child
from './child.vue'export default {components
: {child
},setup () {const msg
= ref('abc')function fn (content
: string
) {msg
.value
+= content
}return {msg
,fn
}}
}
</script
>
<template
><div
><h3
>{{n
}}</h3
><h3
>{{m
}}</h3
><h3
>msg
: {{msg
}}</h3
><h3
>msg2
: {{$attrs
.msg2
}}</h3
><slot name
="xxx"></slot
><button @click
="update">更新
</button
></div
>
</template
><script lang
="ts">import {ref
,defineComponent
} from 'vue'export default defineComponent({name
: 'child',props
: ['msg'],emits
: ['fn'], data () {console
.log('data', this)return {}},beforeCreate () {console
.log('beforeCreate', this)},methods
: {},setup (props
, {attrs
, emit
, slots
}) {console
.log('setup', this)console
.log(props
.msg
, attrs
.msg2
, slots
, emit
)const m
= ref(2)const n
= ref(3)function update () {m
.value
+= 2n
.value
+= 2emit('fn', '++')}return {m
,n
,update
,}},
})
</script
>
6. reactive和ref-的細節問題
- 是Vue3的 composition API中2個最重要的響應式API
- ref用來處理基本類型數據, reactive用來處理對象(遞歸深度響應式)
- 如果用ref對象/數組, 內部會自動將對象/數組轉換為reactive的代理對象
- ref內部: 通過給value屬性添加getter/setter來實現對數據的劫持
- reactive內部: 通過使用Proxy來實現對對象內部所有數據的劫持, 并通過Reflect操作對象內部數據
- ref的數據操作: 在js中要.value, 在模板中不需要(內部解析模板時會自動添加.value)
<template
><h2
>App
</h2
><p
>m1
: {{m1
}}</p
><p
>m2
: {{m2
}}</p
><p
>m3
: {{m3
}}</p
><button @click
="update">更新
</button
>
</template
><script lang
="ts">
import {reactive
,ref
} from 'vue'export default {setup () {const m1
= ref('abc')const m2
= reactive({x
: 1, y
: {z
: 'abc'}})const m3
= ref({a1
: 2, a2
: {a3
: 'abc'}})console
.log(m1
, m2
, m3
)console
.log(m3
.value
.a2
) function update() {m1
.value
+= '--'m2
.x
+= 1m2
.y
.z
+= '++'m3
.value
= {a1
: 3, a2
: {a3
: 'abc---'}}m3
.value
.a2
.a3
+= '==' console
.log(m3
.value
.a2
)}return {m1
,m2
,m3
,update
}}
}
</script
>
7. 計算屬性與監視
- computed函數:
- 與computed配置功能一致
- 只有getter
- 有getter和setter
- watch函數
- 與watch配置功能一致
- 監視指定的一個或多個響應式數據, 一旦數據變化, 就自動執行監視回調
- 默認初始時不執行回調, 但可以通過配置immediate為true, 來指定初始時立即執行第一次
- 通過配置deep為true, 來指定深度監視
- watchEffect函數
- 不用直接指定要監視的數據, 回調函數中使用的哪些響應式數據就監視哪些響應式數據
- 默認初始時就會執行第一次, 從而可以收集需要監視的數據
- 監視數據發生變化時回調
<template
><h2
>App
</h2
>fistName
: <input v
-model
="user.firstName"/><br
>lastName
: <input v
-model
="user.lastName"/><br
>fullName1
: <input v
-model
="fullName1"/><br
>fullName2
: <input v
-model
="fullName2"><br
>fullName3
: <input v
-model
="fullName3"><br
></template
><script lang
="ts">
import {reactive
,ref
,computed
,watch
,watchEffect
} from 'vue'export default {setup () {const user
= reactive({firstName
: 'A',lastName
: 'B'})const fullName1
= computed(() => {console
.log('fullName1')return user
.firstName
+ '-' + user
.lastName
})const fullName2
= computed({get () {console
.log('fullName2 get')return user
.firstName
+ '-' + user
.lastName
},set (value
: string
) {console
.log('fullName2 set')const names
= value
.split('-')user
.firstName
= names
[0]user
.lastName
= names
[1]}})const fullName3
= ref('')watch(user
, () => {fullName3
.value
= user
.firstName
+ '-' + user
.lastName
}, {immediate
: true, deep
: true, })watch(fullName3
, (value
) => {console
.log('watch')const names
= value
.split('-')user
.firstName
= names
[0]user
.lastName
= names
[1]})watch([() => user
.firstName
, () => user
.lastName
, fullName3
], (values
) => {console
.log('監視多個數據', values
)})return {user
,fullName1
,fullName2
,fullName3
}}
}
</script
>
8. 聲明周期對比
vue2聲明周期示圖:
vue3聲明周期示圖:
與 2.x 版本生命周期相對應的組合式 API
- beforeCreate -> 使用 setup()
- created -> 使用 setup()
- beforeMount -> onBeforeMount
- mounted -> onMounted
- beforeUpdate -> onBeforeUpdate
- updated -> onUpdated
- beforeDestroy -> onBeforeUnmount
- destroyed -> onUnmounted
- errorCaptured -> onErrorCaptured
新增的鉤子函數
組合式 API 還提供了以下調試鉤子函數:
- onRenderTracked
- onRenderTriggered
<template
>
<div
class="about"><h2
>msg
: {{msg
}}</h2
><hr
><button @click
="update">更新
</button
>
</div
>
</template
><script lang
="ts">
import {ref
,onMounted
,onUpdated
,onUnmounted
, onBeforeMount
, onBeforeUpdate
,onBeforeUnmount
} from "vue"export default {beforeCreate () {console
.log('beforeCreate()')},created () {console
.log('created')},beforeMount () {console
.log('beforeMount')},mounted () {console
.log('mounted')},beforeUpdate () {console
.log('beforeUpdate')},updated () {console
.log('updated')},beforeUnmount () {console
.log('beforeUnmount')},unmounted () {console
.log('unmounted')},setup() {const msg
= ref('abc')const update = () => {msg
.value
+= '--'}onBeforeMount(() => {console
.log('--onBeforeMount')})onMounted(() => {console
.log('--onMounted')})onBeforeUpdate(() => {console
.log('--onBeforeUpdate')})onUpdated(() => {console
.log('--onUpdated')})onBeforeUnmount(() => {console
.log('--onBeforeUnmount')})onUnmounted(() => {console
.log('--onUnmounted')})return {msg
,update
}}
}
</script
>
<template
><h2
>App
</h2
><button @click
="isShow=!isShow">切換
</button
><hr
><Child v
-if="isShow"/>
</template
><script lang
="ts">
import Child
from './Child.vue'
export default {data () {return {isShow
: true}},components
: {Child
}
}
</script
>
9. 自定義hook函數
-
使用Vue3的組合API封裝的可復用的功能函數
-
自定義hook的作用類似于vue2中的mixin技術
-
自定義Hook的優勢: 很清楚復用功能代碼的來源, 更清楚易懂
-
需求1: 收集用戶鼠標點擊的頁面坐標
hooks/useMousePosition.ts
import { ref
, onMounted
, onUnmounted
} from 'vue'
export default function useMousePosition () {const x
= ref(-1)const y
= ref(-1)const updatePosition = (e
: MouseEvent
) => {x
.value
= e
.pageXy
.value
= e
.pageY
}onMounted(() => {document
.addEventListener('click', updatePosition
)})onUnmounted(() => {document
.removeEventListener('click', updatePosition
)})return {x
, y
}
}
<template
>
<div
><h2
>x
: {{x
}}, y
: {{y
}}</h2
>
</div
>
</template
><script
>import {ref
} from "vue"
import useMousePosition
from './hooks/useMousePosition'export default {setup() {const {x
, y
} = useMousePosition()return {x
,y
,}}
}
</script
>
-
利用TS泛型強化類型檢查
-
需求2: 封裝發ajax請求的hook函數
hooks/useRequest.ts
import { ref
} from 'vue'
import axios
from 'axios'
export default function useUrlLoader
<T>(url
: string) {const result
= ref
<T | null>(null)const loading
= ref(true)const errorMsg
= ref(null)axios
.get(url
).then(response
=> {loading
.value
= falseresult
.value
= response
.data
}).catch(e
=> {loading
.value
= falseerrorMsg
.value
= e
.message
|| '未知錯誤'})return {loading
,result
,errorMsg
,}
}
<template
>
<div
class="about"><h2 v
-if="loading">LOADING...</h2
><h2 v
-else-if="errorMsg">{{errorMsg
}}</h2
><!-- <ul v
-else><li
>id
: {{result
.id
}}</li
><li
>name
: {{result
.name
}}</li
><li
>distance
: {{result
.distance
}}</li
></ul
> --><ul v
-for="p in result" :key
="p.id"><li
>id
: {{p
.id
}}</li
><li
>title
: {{p
.title
}}</li
><li
>price
: {{p
.price
}}</li
></ul
><!-- <img v
-if="result" :src
="result[0].url" alt
=""> -->
</div
>
</template
><script lang
="ts">
import {watch
} from "vue"
import useRequest
from './hooks/useRequest'
interface AddressResult {id
: number
;name
: string
;distance
: string
;
}
interface ProductResult {id
: string
;title
: string
;price
: number
;
}export default {setup() {const {loading
, result
, errorMsg
} = useRequest
<ProductResult
[]>('/data/products.json')watch(result
, () => {if (result
.value
) {console
.log(result
.value
.length
) }})return {loading
,result
, errorMsg
}}
}
</script
>
10. toRefs
把一個響應式對象轉換成普通對象,該普通對象的每個 property 都是一個 ref
應用: 當從合成函數返回響應式對象時,toRefs 非常有用,這樣消費組件就可以在不丟失響應式的情況下對返回的對象進行分解使用
問題: reactive 對象取出的所有屬性值都是非響應式的
解決: 利用 toRefs 可以將一個響應式 reactive 對象的所有原始屬性轉換為響應式的 ref 屬性
<template
><h2
>App
</h2
><h3
>foo
: {{foo
}}</h3
><h3
>bar
: {{bar
}}</h3
><h3
>foo2
: {{foo2
}}</h3
><h3
>bar2
: {{bar2
}}</h3
></template
><script lang
="ts">
import { reactive
, toRefs
} from 'vue'
export default {setup () {const state
= reactive({foo
: 'a',bar
: 'b',})const stateAsRefs
= toRefs(state
)setTimeout(() => {state
.foo
+= '++'state
.bar
+= '++'}, 2000);const {foo2
, bar2
} = useReatureX()return {...stateAsRefs
,foo2
, bar2
}},
}function useReatureX() {const state
= reactive({foo2
: 'a',bar2
: 'b',})setTimeout(() => {state
.foo2
+= '++'state
.bar2
+= '++'}, 2000);return toRefs(state
)
}</script
>
11. ref獲取元素
利用ref函數獲取組件中的標簽元素
功能需求: 讓輸入框自動獲取焦點
<template
><h2
>App
</h2
><input type
="text">---<input type
="text" ref
="inputRef">
</template
><script lang
="ts">
import { onMounted
, ref
} from 'vue'
export default {setup() {const inputRef
= ref
<HTMLElement
|null>(null)onMounted(() => {inputRef
.value
&& inputRef
.value
.focus()})return {inputRef
}},
}
</script
>
Composition API 其他部分
1. shallowReactive 與 shallowRef
- shallowReactive : 只處理了對象內最外層屬性的響應式(也就是淺響應式)
- shallowRef: 只處理了value的響應式, 不進行對象的reactive處理
- 什么時候用淺響應式呢?
- 一般情況下使用ref和reactive即可
- 如果有一個對象數據, 結構比較深, 但變化時只是外層屬性變化 ===> shallowReactive
- 如果有一個對象數據, 后面會產生新的對象來替換 ===> shallowRef
<template
><h2
>App
</h2
><h3
>m1
: {{m1
}}</h3
><h3
>m2
: {{m2
}}</h3
><h3
>m3
: {{m3
}}</h3
><h3
>m4
: {{m4
}}</h3
><button @click
="update">更新
</button
>
</template
><script lang
="ts">
import { reactive
, ref
, shallowReactive
, shallowRef
} from 'vue'
export default {setup () {const m1
= reactive({a
: 1, b
: {c
: 2}})const m2
= shallowReactive({a
: 1, b
: {c
: 2}})const m3
= ref({a
: 1, b
: {c
: 2}})const m4
= shallowRef({a
: 1, b
: {c
: 2}})const update = () => {m4
.value
.a
+= 1}return {m1
,m2
,m3
,m4
,update
,}}
}
</script
>
2. readonly 與 shallowReadonly
- readonly:
- 深度只讀數據
- 獲取一個對象 (響應式或純對象) 或 ref 并返回原始代理的只讀代理。
- 只讀代理是深層的:訪問的任何嵌套 property 也是只讀的。
- shallowReadonly
- 淺只讀數據
- 創建一個代理,使其自身的 property 為只讀,但不執行嵌套對象的深度只讀轉換
- 應用場景:
- 在某些特定情況下, 我們可能不希望對數據進行更新的操作, 那就可以包裝生成一個只讀代理對象來讀取數據, 而不能修改或刪除
<template
><h2
>App
</h2
><h3
>{{state
}}</h3
><button @click
="update">更新
</button
>
</template
><script lang
="ts">
import { reactive
, readonly
, shallowReadonly
} from 'vue'
export default {setup () {const state
= reactive({a
: 1,b
: {c
: 2}})const rState2
= shallowReadonly(state
)const update = () => {rState2
.b
.c
++}return {state
,update
}}
}
</script
>
3. toRaw 與 markRaw
- toRaw
- 返回由 reactive 或 readonly 方法轉換成響應式代理的普通對象。
- 這是一個還原方法,可用于臨時讀取,訪問不會被代理/跟蹤,寫入時也不會觸發界面更新。
- markRaw
- 標記一個對象,使其永遠不會轉換為代理。返回對象本身
- 應用場景:
- 有些值不應被設置為響應式的,例如復雜的第三方類實例或 Vue 組件對象。
- 當渲染具有不可變數據源的大列表時,跳過代理轉換可以提高性能。
<template
><h2
>{{state
}}</h2
><button @click
="testToRaw">測試toRaw
</button
><button @click
="testMarkRaw">測試markRaw
</button
>
</template
><script lang
="ts">
import {markRaw
,reactive
, toRaw
,
} from 'vue'
export default {setup () {const state
= reactive
<any
>({name
: 'tom',age
: 25,})const testToRaw = () => {const user
= toRaw(state
)user
.age
++ }const testMarkRaw = () => {const likes
= ['a', 'b']state
.likes
= markRaw(likes
) setTimeout(() => {state
.likes
[0] += '--'}, 1000)}return {state
,testToRaw
,testMarkRaw
,}}
}
</script
>
4. toRef
- 為源響應式對象上的某個屬性創建一個 ref對象, 二者內部操作的是同一個數據值, 更新時二者是同步的
- 區別ref: 拷貝了一份新的數據值單獨操作, 更新時相互不影響
- 應用: 當要將 某個prop 的 ref 傳遞給復合函數時,toRef 很有用
<template
><h2
>App
</h2
><p
>{{state
}}</p
><p
>{{foo
}}</p
><p
>{{foo2
}}</p
><button @click
="update">更新
</button
><Child
:foo
="foo"/>
</template
><script lang
="ts">
import {reactive
,toRef
,ref
,
} from 'vue'
import Child
from './Child.vue'export default {setup () {const state
= reactive({foo
: 1,bar
: 2})const foo
= toRef(state
, 'foo')const foo2
= ref(state
.foo
)const update = () => {state
.foo
++}return {state
,foo
,foo2
,update
,}},components
: {Child
}
}
</script
>
<template
><h2
>Child
</h2
><h3
>{{foo
}}</h3
><h3
>{{length
}}</h3
>
</template
><script lang
="ts">
import { computed
, defineComponent
, Ref
, toRef
} from 'vue'const component
= defineComponent({props
: {foo
: {type
: Number
,require
: true}},setup (props
, context
) {const length
= useFeatureX(toRef(props
, 'foo'))return {length
}}
})function useFeatureX(foo
: Ref
) {const lenth
= computed(() => foo
.value
.length
)return lenth
}export default component
</script
>
5. customRef
- 創建一個自定義的 ref,并對其依賴項跟蹤和更新觸發進行顯式控制
- 需求: 使用 customRef 實現 debounce 的示例
<template
><h2
>App
</h2
><input v
-model
="keyword" placeholder
="搜索關鍵字"/><p
>{{keyword
}}</p
>
</template
><script lang
="ts">
import {ref
,customRef
} from 'vue'export default {setup () {const keyword
= useDebouncedRef('', 500)console
.log(keyword
)return {keyword
}},
}
function useDebouncedRef
<T>(value
: T, delay
= 200) {let timeout
: number
return customRef((track
, trigger
) => {return {get() {track()return value
},set(newValue
: T) {clearTimeout(timeout
)timeout
= setTimeout(() => {value
= newValue
trigger()}, delay
)}}})
}</script
>
6. provide 與 inject
- provide和inject提供依賴注入,功能類似 2.x 的provide/inject
- 實現跨層級組件(祖孫)間通信
<template
><h1
>父組件
</h1
><p
>當前顏色
: {{color
}}</p
><button @click
="color='red'">紅
</button
><button @click
="color='yellow'">黃
</button
><button @click
="color='blue'">藍
</button
><hr
><Son
/>
</template
><script lang
="ts">
import { provide
, ref
} from 'vue'
import Son
from './Son.vue'
export default {name
: 'ProvideInject',components
: {Son
},setup() {const color
= ref('red')provide('color', color
)return {color
}}
}
</script
>
<template
><div
><h2
>子組件
</h2
><hr
><GrandSon
/></div
>
</template
><script lang
="ts">
import GrandSon
from './GrandSon.vue'
export default {components
: {GrandSon
},
}
</script
>
<template
><h3
:style
="{color}">孫子組件
: {{color
}}</h3
></template
><script lang
="ts">
import { inject
} from 'vue'
export default {setup() {const color
= inject('color')return {color
}}
}
</script
>
7. 響應式數據的判斷
- isRef: 檢查一個值是否為一個 ref 對象
- isReactive: 檢查一個對象是否是由 reactive 創建的響應式代理
- isReadonly: 檢查一個對象是否是由 readonly 創建的只讀代理
- isProxy: 檢查一個對象是否是由 reactive 或者 readonly 方法創建的代理
Composition API vs Option API
1. 使用Option API
在傳統的Vue OptionsAPI中,新增或者修改一個需求,就需要分別在data,methods,computed里修改 ,滾動條反復上下移動
2. 使用Compisition API
我們可以更加優雅的組織我們的代碼,函數。讓相關功能的代碼更加有序的組織在一起
總結
以上是生活随笔為你收集整理的Composition API 使用的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。