Options API的弊端
在Vue2中叮阅,我們編寫組件的方式是Options API:
- Options API的一大特點(diǎn)就是在對應(yīng)的屬性中編寫對應(yīng)的功能模塊嫂伞;
- 比如data定義數(shù)據(jù)展运、methods中定義方法顶别、computed中定義計(jì)算屬性些阅、watch中監(jiān)聽屬性改變狐粱,也包括生命
周期鉤子舀寓;
但是這種代碼有一個(gè)很大的弊端:
- 當(dāng)我們實(shí)現(xiàn)某一個(gè)功能時(shí),這個(gè)功能對應(yīng)的代碼邏輯會(huì)被拆分到各個(gè)屬性中脑奠;
- 當(dāng)我們組件變得更大基公、更復(fù)雜時(shí),邏輯關(guān)注點(diǎn)的列表就會(huì)增長宋欺,那么同一個(gè)功能的邏輯就會(huì)被拆分的很分散轰豆;
- 尤其對于那些一開始沒有編寫這些組件的人來說,這個(gè)組件的代碼是難以閱讀和理解的(閱讀組件的其他人)齿诞;
下面我們來看一個(gè)非常大的組件酸休,其中的邏輯功能按照顏色進(jìn)行了劃分:
- 這種碎片化的代碼使用,理解和維護(hù)這個(gè)復(fù)雜的組件變得異常困難,并且隱藏了潛在的邏輯問題祷杈;
-
并且當(dāng)我們處理單個(gè)邏輯關(guān)注點(diǎn)時(shí)斑司,需要不斷的跳到相應(yīng)的代碼塊中;
如果我們能將同一個(gè)邏輯關(guān)注點(diǎn)相關(guān)的代碼收集在一起會(huì)更好但汞。
這就是Composition API想要做的事情宿刮,以及可以幫助我們完成的事情。也有人把Vue CompositionAPI簡稱為VCA私蕾。
認(rèn)識(shí)Composition API
那么既然知道Composition API想要幫助我們做什么事情僵缺,接下來看一下到底是怎么做呢?
- 為了開始使用Composition API踩叭,我們需要有一個(gè)可以實(shí)際使用它(編寫代碼)的地方磕潮;
- 在Vue組件中,這個(gè)位置就是 setup 函數(shù)容贝;
setup其實(shí)就是組件的另外一個(gè)選項(xiàng):
- 只不過這個(gè)選項(xiàng)強(qiáng)大到我們可以用它來替代之前所編寫的大部分其他選項(xiàng)自脯;
- 比如methods、computed斤富、watch膏潮、data、生命周期等等满力;
接下來我們一起學(xué)習(xí)這個(gè)函數(shù)的使用:
- 函數(shù)的參數(shù)
- 函數(shù)的返回值
setup函數(shù)的參數(shù)
我們先來研究一個(gè)setup函數(shù)的參數(shù)戏罢,它主要有兩個(gè)參數(shù):
- 第一個(gè)參數(shù):
props
- 第二個(gè)參數(shù):
context
props非常好理解屋谭,它其實(shí)就是子組件接收的從父組件傳遞過來的屬性
,會(huì)被放到1props對象
中龟糕,我們在setup函數(shù)
中如果需要使用
桐磁,那么就可以直接通過props
參數(shù)獲取:
- 對于定義props的類型讲岁,我們還是和之前的規(guī)則是一樣的我擂,在props選項(xiàng)中定義;
- 并且在template中依然是可以正常去使用props中的屬性缓艳,比如message校摩;
- 如果我們在setup函數(shù)中想要使用props,那么不可以通過 this 去獲冉滋浴(后面我會(huì)講到為什么)衙吩;
- 因?yàn)閜rops有直接作為參數(shù)傳遞到setup函數(shù)中,所以我們可以直接通過參數(shù)來使用即可溪窒;
另外一個(gè)參數(shù)是context
坤塞,我們也稱之為是一個(gè)SetupContext
,它里面包含三個(gè)屬性:
attrs
:為一個(gè)對象澈蚌,存儲(chǔ)著所有的從父組件傳遞過來的非props的attribute摹芙;
slots
:父組件傳遞過來的插槽(這個(gè)在以渲染函數(shù)返回時(shí)會(huì)有作用,后面會(huì)講到)宛瞄;
emit
:當(dāng)我們組件內(nèi)部需要發(fā)出事件時(shí)會(huì)用到emit(因?yàn)槲覀儾荒茉L問this浮禾,所以不可以通過 this.$emit發(fā)出事件);
setup函數(shù)的返回值
setup既然是一個(gè)函數(shù)份汗,那么它也可以有返回值盈电,它的返回值用來做什么呢?
- setup的返回值可以在
模板template
中被使用杯活; - 也就是說我們可以通過setup的返回值來替代data選項(xiàng)匆帚;
甚至是我們可以返回一個(gè)執(zhí)行函數(shù)
來代替在methods
中定義的方法
:
setup() {
let counter = 100
const increment = () => {
counter++
}
const decrement = () => {
counter--
}
return {
counter,
increment,
decrement
}
}
但是,如果我們將 counter 在 increment 或者 decrement進(jìn)行操作時(shí)轩猩,是否可以實(shí)現(xiàn)界面的響應(yīng)式呢卷扮?
- 答案是不可以荡澎;
- 這是因?yàn)閷τ谝粋€(gè)定義的變量來說均践,默認(rèn)情況下,Vue并不會(huì)跟蹤它的變化摩幔,來引起界面的響應(yīng)式操作彤委;
案例
App.vue
所有在template模板
中使用的變量
或方法
(除了props
和$attrs
中的屬性),都得在setup函數(shù)中
返回
<template>
<div>
<!--父組件在使用子組件home時(shí)或衡,除了給其傳了內(nèi)部接收的props的屬性message,title外焦影,還額外傳了兩個(gè)非props屬性id, class-->
<home
message="hahahh"
title="標(biāo)題"
id="home"
class="homeClass"
@change="change"
/>
</div>
</template>
<script>
import Home from "./Home.vue";
export default {
name: "App",
components: {
Home,
},
setup() {
const change = (value) => {
console.log("監(jiān)聽到了change事件", value);
};
return {
//所有在template模板中使用的變量或方法(除了props和$attrs中的屬性)车遂,都得在setup函數(shù)中返回
change,
};
},
};
</script>
<style></style>
Home.vue
父組件傳遞給子組件的非props屬性
在template
中使用,這些屬性都存儲(chǔ)在$attrs
對象中,可以通過attrs.屬性名
獲取
父組件傳遞給子組件的非props屬性
在setup函數(shù)
中獲取斯辰,這些屬性都存儲(chǔ)在setup函數(shù)
的第二個(gè)參數(shù)對象context
的attrs
屬性中,可以通過context.attrs.屬性名
獲取
父組件傳遞給子組件的props屬性
在setup函數(shù)
中獲取舶担,這些屬性都存儲(chǔ)在setup函數(shù)
的第一個(gè)參數(shù)對象props
中,可以通過props.屬性名
獲取
在setup函數(shù)中,子組件向父組件發(fā)射事件彬呻,可以通過context.emit
發(fā)射事件
<template>
<div>
<h2>{{ title }}</h2>
<p>{{ message }}</p>
<!-- 下面展示父組件傳遞給子組件的非props屬性在template中的使用衣陶,這些屬性都存儲(chǔ)在$attrs對象中 -->
<div>id: {{ $attrs.id }} - class: {{ $attrs.class }}</div>
<slot></slot>
</div>
</template>
<script>
export default {
props: {
message: {
type: String,
required: true,
},
title: {
type: String,
default: "",
},
},
emits: ["change"],
setup(props, context) {
const { attrs, slots, emit } = context;
//在setup中獲取props中屬性,通過setup函數(shù)的第一個(gè)參數(shù)獲取
console.log("props", props, props.message, props.title);
//父組件傳遞給子組件的非props屬性在setup中使用闸氮,這些屬性都存儲(chǔ)在context.attrs對象中
console.log("attrs", attrs, attrs.id, attrs.class);
//父組件插入子組件插槽中的內(nèi)容
console.log("slots", slots);
emit("change", "今天天氣不錯(cuò)"); //emit用來向父組件發(fā)射事件
},
};
</script>
<style lang="scss" scoped></style>
setup不可以使用this
官方關(guān)于this有這樣一段描述:
- 表達(dá)的含義是this并沒有指向當(dāng)前組件實(shí)例剪况;
- 并且在setup被調(diào)用之前,data蒲跨、computed译断、methods等都沒有被解析;
-
所以無法在setup中獲取this或悲;