前言
options Api的弊端
在Vue2中,我們編寫(xiě)組件的方式是Options APl:
- Options API的一大特點(diǎn)就是在
對(duì)應(yīng)的屬性
中編寫(xiě)對(duì)應(yīng)的功能模塊
;- 比如
data定義數(shù)據(jù)
、methods中定義方法
、computed中定義計(jì)算屬性
、watch中監(jiān)聽(tīng)屬性改變
,也包括生命周期鉤子
;
但是這種代碼有一個(gè)很大的弊端:
- 當(dāng)我們
實(shí)現(xiàn)某一個(gè)功能
時(shí),這個(gè)功能對(duì)應(yīng)的代碼邏輯
會(huì)被拆分到各個(gè)屬性
中;- 當(dāng)我們
組件變得更大、更復(fù)雜
時(shí),邏輯關(guān)注點(diǎn)的列表
就會(huì)增長(zhǎng),那么同一個(gè)功能的邏輯就會(huì)被拆分的很分散
;- 尤其對(duì)于那些一
開(kāi)始沒(méi)有編寫(xiě)這些組件的人
來(lái)說(shuō),這個(gè)組件的代碼是難以閱讀和理解的
(閱讀組件的其他人);
下面我們來(lái)看一個(gè)非常大的組件,其中的邏輯功能按照顏色進(jìn)行了劃分:
- 這種
碎片化的代碼
使用理解和維護(hù)這個(gè)復(fù)雜的組件
變得異常困難,并且隱藏了潛在的邏輯問(wèn)題
;- 并且當(dāng)我們
處理單個(gè)邏輯關(guān)注點(diǎn)
時(shí),需要不斷的跳到相應(yīng)的代碼
塊中;
如果我們能將
同一個(gè)邏輯關(guān)注點(diǎn)相關(guān)的代碼
收集在一起
會(huì)更好。
這就是Composition API想要做的事情,以及可以幫助我們完成的事情。
認(rèn)識(shí)composition Api
那么既然知道Composition API想要幫助我們做什么事情,接下來(lái)看一下到底是怎么做呢?
- 為了開(kāi)始使用Composition API,我們需要有一個(gè)可以實(shí)際使用它
(編寫(xiě)代碼)的地方
; - 在Vue組件中,這個(gè)位置就是
setup函數(shù)
;
setup其實(shí)就是組件的另外一個(gè)選項(xiàng):
- 只不過(guò)這個(gè)選項(xiàng)強(qiáng)大到我們可以
用它來(lái)替代之前所編寫(xiě)的大部分其他選項(xiàng)
; - 比如
methods、computed、watch、data、生命周期
等等;
接下來(lái)我們一起學(xué)習(xí)這個(gè)函數(shù)的使用:
- 函數(shù)的參數(shù)
- 函數(shù)的返回值
Set up函數(shù)的基本使用
set up函數(shù)的參數(shù)
我們先來(lái)研究一個(gè)setup函數(shù)的參數(shù),它主要有兩個(gè)參數(shù):
- 第一個(gè)參數(shù):
props
- 第二個(gè)參數(shù):
context
props非常好理解,它其實(shí)就是父組件傳遞過(guò)來(lái)的屬性會(huì)被放到props對(duì)象中,我們在setup中如果需要使用,那么就可以直接通過(guò)props參數(shù)獲取:
- 對(duì)于
定義props的類型
,我們還是和之前的規(guī)則是一樣的,在props選項(xiàng)中定義
;- 并且
在template中
依然是可以正常去使用props中的屬性
,比如message;- 如果我們
在setup函數(shù)中想要使用props
,那么不可以通過(guò)this去獲取
(后面我會(huì)講到為什么);- 因?yàn)閜rops有直接
作為參數(shù)傳遞到setup函數(shù)
中,所以我們可以直接通過(guò)參數(shù)
來(lái)使用即可;
另外一個(gè)參數(shù)是context,我們也稱之為是一個(gè)SetupContext,它里面包含三個(gè)屬性:
attrs
:所有的非prop的attribute;slots
:父組件傳遞過(guò)來(lái)的插槽(這個(gè)在以渲染函數(shù)返回時(shí)會(huì)有作用,后面會(huì)講到);emit
:當(dāng)我們組件內(nèi)部需要發(fā)出事件時(shí)會(huì)用到emit(因?yàn)槲覀儾荒茉L問(wèn)this,所以不可以通過(guò) this.$emit發(fā)出事件);
set up函數(shù)的返回值
setup既然是一個(gè)函數(shù),那么它也可以有返回值,它的返回值用來(lái)做什么呢?
- setup的返回值可以在
模板template中被使用
; - 也就是說(shuō)我們可以
通過(guò)setup的返回值來(lái)替代data選項(xiàng)
;
甚至是我們可以返回一個(gè)執(zhí)行函數(shù)來(lái)代替在methods中定義的方法:
- 下面通過(guò)從一個(gè)計(jì)數(shù)器案例來(lái)體驗(yàn)下:
<template>
<div class="app">
<h2>當(dāng)前計(jì)數(shù): {{ counter }}</h2>
<button @click="increment">+</button>
<button @click="decrement">-</button>
</div>
</template>
<script>
export default {
// 使用setup函數(shù)
setup() {
//1.定義counter的內(nèi)容
// 默認(rèn)定義的數(shù)據(jù)都不是響應(yīng)式數(shù)據(jù)
let counter = 100
// setup函數(shù)定義函數(shù)(方法)
const increment = () => {
counter++
}
// setup函數(shù)定義函數(shù)(方法)
const decrement = () => {
counter--
}
// 外部要使用的數(shù)據(jù)需要通過(guò)return導(dǎo)出
return {
counter,
increment,
decrement
}
}
}
</script>
運(yùn)行上述代碼,發(fā)現(xiàn)點(diǎn)擊 increment 或者 decrement按鈕進(jìn)行操作時(shí),發(fā)現(xiàn)counter展示的數(shù)值沒(méi)有發(fā)生變化:
因?yàn)?code>默認(rèn)定義的數(shù)據(jù)不是響應(yīng)式數(shù)據(jù),即對(duì)于一個(gè)定義的變量來(lái)說(shuō),默認(rèn)情況下,Vue并不會(huì)跟蹤它的變化,來(lái)引起界面的響應(yīng)式操作;
Set up中數(shù)據(jù)的響應(yīng)式
如果想為在setup中定義的數(shù)據(jù)提供響應(yīng)式的特性,那么我們有如下兩種常見(jiàn)的方案:
1. Reactive API
如果想為在setup中定義的數(shù)據(jù)提供響應(yīng)式的特性,那么我們可以使用reactive的函數(shù):
<template>
<div class="app">
<h2>message:{{ message }}</h2>
<button @click="changeMessage">修改message</button>
</div>
<hr>
<h2>賬號(hào):{{ account.username }}</h2>
<h2>密碼:{{ account.password }}</h2>
<button @click="changeAccount">修改賬戶名</button>
<hr>
</template>
<script>
import { reactive, ref } from "vue";
export default {
setup() {
// 1.定義普通的數(shù)據(jù)
// 缺點(diǎn):數(shù)據(jù)不是響應(yīng)的
let message = "hello world";
function changeMessage() {
message = "message已被修改"//不生效
console.log(222);//222
}
// 2.定義響應(yīng)式的數(shù)據(jù)
// 2.1 reactive函數(shù):定義復(fù)雜類型的數(shù)據(jù)(不常用)
const account = reactive({
username: "wxx",
password: "1212135"
})
function changeAccount() {
account.username = "颯颯"//生效
}
return {
message,
changeMessage,
account,
changeAccount,
}
}
}
</script>
那么這是什么原因呢?為什么就可以變成響應(yīng)式的呢?
- 這是因?yàn)楫?dāng)我們
使用reactive函數(shù)處理我們的數(shù)據(jù)之后
,數(shù)據(jù)再次被使用
時(shí)就會(huì)進(jìn)行依賴收集
;- 當(dāng)
數(shù)據(jù)發(fā)生改變
時(shí),所有收集到的依賴
都是進(jìn)行對(duì)應(yīng)的響應(yīng)式操作
(比如更新界面);- 事實(shí)上,我們編寫(xiě)的
data選項(xiàng)
,也是在內(nèi)部交給了reactive函數(shù)
將其編程響應(yīng)式對(duì)象的;
2. Ref API
reactive API對(duì)傳入的類型是有限制的,它要求我們必須傳入的是一個(gè)對(duì)象或者數(shù)組類型:
- 如果我們傳入一個(gè)
基本數(shù)據(jù)類型(String、Number、Boolean)會(huì)報(bào)一個(gè)警告
;
這個(gè)時(shí)候Vue3給我們提供了另外一個(gè)APl: ref API
- ref 會(huì)返回一個(gè)
可變的響應(yīng)式對(duì)象
,該對(duì)象作為一個(gè)響應(yīng)式的引用
維護(hù)著它內(nèi)部的值
,這就是ref名稱的來(lái)源
;- 它內(nèi)部的值是
在ref的 value屬性
中被維護(hù)的;
使用示例:
<template>
<!-- 默認(rèn)情況下載template中使用ref時(shí),vue會(huì)自動(dòng)對(duì)其進(jìn)行解包(取出其中value) -->
<h2>當(dāng)前計(jì)數(shù):{{ counter }}</h2>
<button @click="increment">+1</button>
</template>
<script>
import { ref } from "vue";
export default {
setup() {
// 2.2 Ref函數(shù):定義簡(jiǎn)單類型的數(shù)據(jù)(也可以定義復(fù)雜類型數(shù)據(jù))
//錯(cuò)誤寫(xiě)法: const counter = ref(0);也能實(shí)現(xiàn)變動(dòng),因?yàn)樾薷牡氖莄ounter的value值不少修改的counter本身
let counter = ref(0)
function increment() {
// 錯(cuò)誤寫(xiě)法:counter++
counter.value++
}
return {
counter,
increment
}
}
}
</script>
這里有兩個(gè)注意事項(xiàng):
- 在
模板中引入ref的值
時(shí),Vue會(huì)自動(dòng)幫助我們進(jìn)行解包
操作,所以我們并不需要在模板中通過(guò)ref.value
的方式來(lái)使用;- 但是在
setup函數(shù)內(nèi)部
,它依然是一個(gè)ref引用
,所以對(duì)其進(jìn)行操作時(shí),我們依然需要使用ref.value的方式
;
3. ref和reactive的開(kāi)發(fā)
- 常見(jiàn)使用reactive情況:
常見(jiàn)使用ref情況:
setup中的其他函數(shù)(了解)
1. readonly函數(shù)
先來(lái)看下邊的代碼:
- 在下面的示例中,通過(guò)props
接收到了父組件傳遞過(guò)來(lái)的數(shù)據(jù)
后,直接在當(dāng)前組件進(jìn)行了修改
,這樣是違背了單向數(shù)據(jù)流
的
如上述代碼所示:
我們通過(guò)reactive或者ref可以獲取到一個(gè)響應(yīng)式的對(duì)象,但是某些情況下,我們傳入給其他地方(組件)的這個(gè)響應(yīng)式對(duì)象希望在另外一個(gè)地方(組件)被使用,但是不能被修改,這個(gè)時(shí)候如何防止這種情況的出現(xiàn)呢?
- Vue3為我們提供了
readonly的方法
;readonly會(huì)返回原始對(duì)象的只讀代理
〈也就是它依然是一個(gè)Proxy,這是一個(gè)proxy的set方法被劫持
,并且不能對(duì)其進(jìn)行修改);
在開(kāi)發(fā)中常見(jiàn)的readonly方法會(huì)傳入三個(gè)類型的參數(shù):
- 類型一:
普通對(duì)象
;- 類型二:
reactive返回的對(duì)象
;- 類型三:
ref的對(duì)象
;
在readonly的使用過(guò)程中,有如下規(guī)則:
readonly返回的對(duì)象都是不允許修改的, 但是經(jīng)過(guò)readonly處理的原來(lái)的對(duì)象是允許被修改的;
- 比如 const info = readonly(obj),
info對(duì)象是不允許被修改
的;- 但是可以通過(guò)修改obj來(lái)修改info, obj被修改時(shí),readonly返回的info對(duì)象也會(huì)被修改;
- 但是我們不能去修改readonly返回的對(duì)象info;
setup() {
const info = reactive({
name: "chenyq",
age: 18,
height: 1.88
})
// 為info包裹一個(gè)readonly, 子組件就無(wú)法修改
const newInfo = readonly(info)
console.log(newInfo)
return {
info,
changeInfo,
newInfo
}
}
2. Reactive判斷的API(了解)
isProxy
檢查對(duì)象`是否是由reactive或 readonly創(chuàng)建的proxy。
isReactive
檢查對(duì)象是否是由reactive創(chuàng)建的響應(yīng)式代理:
如果該代理是readonly創(chuàng)建的,但包裹了由reactive創(chuàng)建的另一個(gè)代理,它也會(huì)返回true;
isReadonly
檢查對(duì)象是否是由readonly 創(chuàng)建的只讀代理。
toRaw
返回reactive或 readonly代理的原始對(duì)象(不建議保留對(duì)原始對(duì)象的持久引用。請(qǐng)謹(jǐn)慎使用)。
shallowReactive
創(chuàng)建一個(gè)響應(yīng)式代理,它跟蹤其自身property 的響應(yīng)性,但不執(zhí)行嵌套對(duì)象的深層響應(yīng)式轉(zhuǎn)換(深層還是原生對(duì)象)。
shallowReadonly
創(chuàng)建一個(gè)proxy,使其自身的property為只讀,但不執(zhí)行嵌套對(duì)象的深度只讀轉(zhuǎn)換(深層還是可讀 可寫(xiě)的)。
3. toRef(s)函數(shù)
如果我們希望在模板中展示name,age
等數(shù)據(jù)的值不是info.name,info.age這樣的形式
,而是直接使用所有對(duì)其解構(gòu)
,如下代碼示例:
setup() {
const info = reactive({
name: "sevgilid",
age: 19,
height: 1.87
})
const { name, age, height } = info
}
我們會(huì)發(fā)現(xiàn)直接解構(gòu)后
無(wú)論是修改解構(gòu)后的變量,還是修改reactive返回的state對(duì)象,數(shù)據(jù)都不再是響應(yīng)式
的:
那么如何讓解構(gòu)出來(lái)的屬性變成響應(yīng)式
的呢?這就需要使用到toRefs
和toRef函數(shù):
toRefs 函數(shù)
可以將一個(gè)響應(yīng)式對(duì)象
轉(zhuǎn)換為一個(gè)基本類型的對(duì)象
,并且對(duì)象中每個(gè)屬性都是一個(gè)單獨(dú)的源,并且可以進(jìn)行解構(gòu)和響應(yīng)性訪問(wèn)toRef 函數(shù)
可以將一個(gè)響應(yīng)式對(duì)象中的 指定屬性
轉(zhuǎn)換為一個(gè)新的響應(yīng)式數(shù)據(jù)
,這個(gè)新的數(shù)據(jù)可以獨(dú)立地更新,并且對(duì)原響應(yīng)式對(duì)象不會(huì)造成影響;
- 這個(gè)函數(shù)
接收對(duì)象
和鍵名稱兩個(gè)參數(shù)
,返回一個(gè)帶有 value 屬性的 ref 對(duì)象\
代碼示例:
<template>
<div class="app">
<!-- <h2>info:{{ info.name }}-{{ info.age }}</h2> -->
<h2>info:{{ name }}-{{ age }}-{{ height }}</h2>
<button @click="age++">修改age</button>
</div>
</template>
<script>
import { reactive, toRefs, toRef } from 'vue';
export default {
setup() {
const info = reactive({
name: "sevgilid",
age: 18,
height: 1.88
})
// reactive被解構(gòu)后會(huì)變成普通的值,失去響應(yīng)式
// 使用toRefs,toRef方法就可以
const { name, age } = toRefs(info)
// 單獨(dú)對(duì)一個(gè)結(jié)構(gòu)
const height = toRef(info, "height")
return {
name,
age,
height
}
}
}
setup中禁用this
Vue 3 中的 setup 函數(shù)是一個(gè)新的組件選項(xiàng)
。它允許我們?cè)诮M件渲染之前執(zhí)行一些前置操作,比如數(shù)據(jù)處理、事件綁定等;
與 Vue 2.x 中的 data、computed、methods 等屬性不同,
setup 函數(shù)只接收 props 作為參數(shù),并且不能訪問(wèn) this
為什么不能使用this:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-480493.html
- 在 Vue 3 中,
模板編譯的過(guò)程
發(fā)生了很大的變化
,這就導(dǎo)致了this 不能再指向 Vue 實(shí)例對(duì)象
;- 在 Vue 2.x 中,我們可以通過(guò) this.$xxx 訪問(wèn)全局實(shí)例,但是在 Vue 3 中,由于模板編譯的變化,我們需要使用 provide 和 inject 手動(dòng)注入/引用全局實(shí)例對(duì)象,而不能再通過(guò) this 來(lái)訪問(wèn)它們。
下面的代碼演示了 setup 函數(shù)內(nèi)使用 this 的錯(cuò)誤示例:文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-480493.html
export default {
setup() {
console.log(this.$route) // 無(wú)法訪問(wèn) this
}
}
到了這里,關(guān)于【vue3】11-Vue 3中的Composition Api(一)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!