Composition API 是以逻辑功能来分割程序码,像是写原生 JavaScript 一样,我们会把实现同样功能的程序码写在附近。但 Options API 是以程序码的性质来分割程序码,例如有 3 个函式各自用来实现不同功能,但如果它们都是 computed
函式,就全都一起写在 computed
属性里。所以会产生以下问题:
关於这个题目会分两篇来写,这篇会整理 Composition API 的概念和语法。下一篇就会以实战为主,试试改写 Options API 例子。
Options API 是根据程序的性质来分割程序码。
export default{
props: {},
components: {},
data() {
// 所有资料
},
computed() {
// filter todos 功能
},
mounted() {
// 显示 todos 功能
},
methods() {
// 删除 todos 功能
}
}
但是,Compositions API 是按逻辑来分割程序码。
export default {
setup() {
// 1. 显示 todos 的功能
// ...
// 2. filter todos 的功能
// ...
// 3. 删除 todos 的功能
// ....
}
}
概念如下图一样,用不同颜色代表不同功能需求。 Vue 2 的 options API 的写法明显会比较难阅读:
在 options API,需要用 mixin 来引入可重用的程序码。但在大型专案中,有机会会在一个元件里引入很多 mixin,以致以下问题:
Vue 3 的 composition API 就能解决 mixin 的问题。假设现在我要重用 serachKeyword 此功能
composables/ searchKeyword.js
export default function searchKeyword(keyword, key, list){
const result = list.find( item => item[key] === keyword)
return {
result
}
}
Home.vue
import searchKeyword from '@/composables/searchKeyword'
export default{
setup() {
const { result } = searchKeyword('tshirt', 'title', [{ title: 'hat', price: 100}, {title: 'tshirt', price: 200}])
console.log(result); // {title: 'tshirt', price: 200}
}
}
以上是一个很简单例子,searchKeyword 是用来找出在 list 中合乎 keyword 的那笔资料。以上例子很清晰看到,result 的值是来自 searchKeyword
这个可重用的函式。而且,把它 import 进来 Home.vue 时,我把它也可以改名,不一定用 searchKeyword 这个名称。因此,比起 Vue 2 的 mixin 更好用。
起手式是建立一个 setup 函式,此函式会在 app
挂载在 DOM 上後,并在元件建立前(created 生命周期)执行,而且只会执行一次。
export default {
setup(props, context) {
// 所有程序码写在这里
return {
// 所有在模版上会使用的资料、函式
}
}
}
props
就是用来接收外层资料。slot
, attrs
, emit
, expose
。注意,因 setup
是在元件建立前执行,所以只可使用: props
、slot
、 attrs
、 emit
、 expose
。不可使用: data
、computed
、methods
、refs
(模版用 refs)
setup
函式会回传一个物件,里面要放所有在模版里会用到的资料或函式:
<template>
<div>
<p>{{ user }} </p>
<button @click="greeting" type="button">Say Hi!</button>
</div>
</template>
export default {
setup() {
const user = 'Alysa'
const greeting = () => {
alert('Hi I am a front-end developer')
}
return {
greeting, user
}
}
}
如果资料或函式不在 return
物件里,模版就不能使用。
如果使用解构赋值的手法,会导致该 props 的资料不再是响应式。举例说,要把在外层(App.vue)的 count
传入内层(List.vue):
App.vue
<template>
<p>App: {{ n }} </p>
<List :count="n"></List>
</template>
export default {
components: {
List
},
setup() {
const n = ref(1)
// 每 1 秒加 1
setInterval( () => n.value++,1000)
return {
n
}
}
}
List.vue
<template>
<p>List: {{ count }} </p>
</template>
export default {
props: {
count: Number
},
setup(props) {
// count 失去响应式,不会再更新!
const { count } = props
return {
count
}
}
}
结果:
App 里的 count
目前已经累加到 5,但 List 里的 count
仍然是 1。
toRef
或 toRefs
包装const count = toRef(props, 'count')
或者
// 使用解构赋值建立 count 变数
const { count } = toRefs(props)
结果就能保持响应式,外层和内层的 count 数值同步:
此文较後部分会再详细讲解两者的差异和用法。
在 Vue 2 时,我们全都放到 data
属性里就行了。但现在 Vue 3 里就需要使用 ref()
或 reactive()
来建立响应式资料。
假设有 user、todos 这两笔资料。
Vue 2 做法:
data() {
return{
user: 'Alysa',
todos: ['Watch Netflix', 'Buy dinner']
}
}
Vue 3 做法:
setup() {
const user = ref('Alysa')
const todos = reactive(['Watch Netflix', 'Buy dinner'])
// 用 ref 也可以,看你个人偏好
return {
user,todos
}
}
ref
的接收一个参数,可以是任何型别。ref
无法监听阵列或物件内部属性的变更。(硬要监听的话用 watch 的 deep true 也可以)ref
会回传一个响应式物件,里面只有 value
这个属性。因此,取值时的写法如下:const user = ref('Alysa')
console.log(user.value) // Alysa
reactive
的参数只能是阵列或物件。reactive
可以深层监听阵列或物件内部属性的变更。.value
。因为 reactive
会把整个物件或阵列回传回来。个人偏好是用 ref 定义基本型别资料,用 reactive 定义物件、阵列资料。但这也取决於公司团队做法,也有听说过由头到尾都是用 ref 的做法。
上面提及过,可使用 toRef
或 toRefs
来保持 props
是响应式。此两种语法是针对用 reactive
定义的物件。
reactive
原资料修改,画面会变化。但 toRef
/ toRefs
修改时,画面不会变化。reactive
原资料修改时,toRef
/ toRefs
会随之而变化。反之,当 toRef
/ toRefs
改动时,原资料不会受影响。toRef
接收两个参数,回传一个值。toRefs
只会接收一个参数,回传一个物件。const x = toRef(物件, 属性)
toRefs
只接收一个参数,回传一个物件:
const x = toRefs(物件)
最後,Vue 3 新增了设定资料为唯读的功能。这能避免在多人团队开发时,不小心修改了某些函式里的值,以致程序出错。
const todos = reactive(['Watch Netflix', 'Buy dinner'])
const copyTodos = readonly(todos)
const edit = () => {
copyTodos[0] = 'sleep'
}
edit() //Set operation on key "0" failed: target is readonly
ref
的资料也一样:
const name = ref('Alysa')
const copyName = readonly(name)
setUp()
、ref
/ reactive
来建立资料等等。ref,toRef,toRefs三者的使用及区别
Vue 3 - Composition API
Mike - 2021 Vue 3 专业职人 入门篇
<<: #22-掰惹Gif!用Sprite雪碧图做动画! (CSS & Canvas)
>>: Day23 :【TypeScript 学起来】先了解 ES6 Class
GitHub Repo https://github.com/b2etw/Spring-Kotlin...
Backup 文章 https://hackmd.io/@WePlus/Sky0eQUNF Revi...
假设今天再做某种数位信号处理时,不小心用到了 arctan(y/x) 函数,那麽当然可以用泰勒展开得...
1. 在WebMvc专案新增购物车服务的功能 1.1 新增ViewComponent CartLis...
1.图层有"锁头"就不能被更改,记得开锁头-------------------...