組合API
前言
- 組合式api(Composition API)算是vue3對我們開發(fā)者來說非常有價值的一個api更新。
- 注意,vue3中仍可以使用選項API冲呢。
一鸥咖、選項API和組合API
選項API
各個選項都有固定的書寫位置燕鸽,data選項寫響應式數據,methods選項寫方法函數...啼辣,一個功能邏輯的代碼分散啊研。
優(yōu)點:寫代碼的位置已經約定好,結構清晰
缺點:代碼組織性差鸥拧,相似的邏輯代碼不便于復用党远,邏輯復雜代碼多了不好閱讀,同一功能的上下文代碼難找富弦。
組合API
- 特定功能相關的所有東西都寫在一起沟娱,同一功能代碼塊集中。
- 優(yōu)點:
- 可以快讀定位到某個功能的所有相關代碼舆声。
- 功能復雜花沉,代碼量大,我們還可以進行邏輯拆分處理媳握,功能封裝碱屁。
組合API功能抽離,封裝:
二蛾找、生命周期函數
選項式API | 組合式API |
---|---|
beforeCreate |
不需要(直接寫到setup(創(chuàng)建實例前) 函數中) |
created |
不需要(直接寫到setup(創(chuàng)建實例前) 函數中) |
beforeMount |
onBeforeMount 掛載DOM前 |
mounted |
onMounted 掛載DOM后 |
beforeUpdate |
onBeforeUpdate 更新組件前 |
updated |
onUpdated 更新組件后 |
beforeDestroyed |
onBeforeUnmount 卸載銷毀前 |
destroyed |
onUnmounted 卸載銷毀后 |
總結: 組合API的生命周期鉤子有7個娩脾,可以多次使用同一個鉤子,執(zhí)行順序和書寫順序相同打毛。
三柿赊、組合API基礎
3.1 setup入口函數
setup
函數是一個新的組件選項,作為組件中組合式API 的起點(入口)setup
中不能使用 this幻枉, this 指向 undefinedsetup
函數只會在組件初始化的時候執(zhí)行一次setup
函數在beforeCreate
生命周期鉤子執(zhí)行之前執(zhí)行export default { setup () { console.log('setup執(zhí)行了') console.log(this) }, beforeCreate() { console.log('beforeCreate執(zhí)行了') console.log(this) } }
3.2 reactive函數
- 作用:
reactive
是一個函數碰声,接收一個普通的對象傳入,把對象數據轉化為響應式對象并返回
使用步驟
- 從vue框架中導入
reactive
函數 - 在
setup
函數中調用reactive
函數并將對象數據傳入 - 在
setup
函數中把reactive
函數調用完畢之后的返回值以對象的形式返回出去
3.3 toRef函數
toRef
是函數熬甫,轉換響應式對象中某個屬性為單獨響應式數據胰挑,并且值是關聯的。
3.4 toRefs函數
- 場景: 經過
reactive
函數處理之后返回的對象,如果給這個對象解構或者展開瞻颂,會讓數據丟失響應式的能力豺谈,為了解決這個問題需要引入toRefs
函數,使用 toRefs函數 可以保證該對象展開的每個屬性都是響應式的贡这。
3.5 ref函數
- 作用:ref是一個函數茬末,接受一個簡單類型或者復雜類型的傳入并返回一個響應式且可變的 ref 對象
使用步驟
- 從vue框架中導出ref函數
- 在
setup
函數中調用ref函數并傳入數據(簡單類型或者復雜類型) - 在
setup
函數中把ref函數調用完畢的返回值以對象的形式返回出去 - 注意:在
setup
函數中使用ref結果,需要通過.value
訪問盖矫,模板中使用不需要加.value
四丽惭、組合API
4.1 computed函數
- computed函數,是用來定義計算屬性的辈双,計算屬性不能修改吐根。
計算屬性兩種用法:
- 給
computed
傳入函數,返回值就是計算屬性的值
- 給
computed
傳入對象辐马,get獲取計算屬性的值,set監(jiān)聽計算屬性改變局义。
4.2 watch函數
- watch函數喜爷,是用來定義偵聽器的
監(jiān)聽ref定義的響應式數據
監(jiān)聽多個響應式數據數據
監(jiān)聽reactive定義的響應式數據
監(jiān)聽reactive定義的響應式數據,某一個屬性
深度監(jiān)聽
默認執(zhí)行
<template>
<div class="container">
<div>
<p>count的值:{{count}}</p>
<button @click="add">改數據</button>
</div>
<hr>
<div>
<p>{{obj.name}}</p>
<p>{{obj.age}}</p>
<p>{{obj.brand.name}}</p>
<button @click="updateName">改名字</button>
<button @click="updateBrandName">改品牌名字</button>
</div>
</div>
</template>
<script>
import { reactive, ref, watch } from 'vue'
export default {
name: 'App',
setup () {
const count = ref(0)
const add = () => {
count.value++
}
// 當你需要監(jiān)聽數據的變化就可以使用watch
// 1. 監(jiān)聽一個ref數據
// 1.1 第一個參數 需要監(jiān)聽的目標
// 1.2 第二個參數 改變后觸發(fā)的函數
// watch(count, (newVal,oldVal)=>{
// console.log(newVal,oldVal)
// })
const obj = reactive({
name: 'ls',
age: 10,
brand: {
id: 1,
name: '寶馬'
}
})
const updateName = () => {
obj.name = 'zs'
}
const updateBrandName = () => {
obj.brand.name = '奔馳'
}
// 2. 監(jiān)聽一個reactive數據
watch(obj, ()=>{
console.log('數據改變了')
})
watch(()=>obj.brand, ()=>{
console.log('brand數據改變了')
},{
// 5. 需要深度監(jiān)聽
deep: true,
// 6. 想默認觸發(fā)
immediate: true
})
// 3. 監(jiān)聽多個數據的變化
// watch([count, obj], ()=>{
// console.log('監(jiān)聽多個數據改變了')
// })
// 4. 此時監(jiān)聽對象中某一個屬性的變化 例如:obj.name
// 需要寫成函數返回該屬性的方式才能監(jiān)聽到
// watch(()=>obj.name,()=>{
// console.log('監(jiān)聽obj.name改變了')
// })
return {count, add, obj, updateName, updateBrandName}
}
}
</script>
4.3 ref屬性
- 使用ref屬性綁定DOM或組件
獲取單個DOM或者組件:
<template>
<div class="container">
<!-- vue2.0 獲取單個元素 -->
<!-- 1. 通過ref屬性綁定該元素 -->
<!-- 2. 通過this.$refs.box獲取元素 -->
<!-- <div ref="box">我是box</div> -->
<!-- vue2.0 獲取v-for遍歷的多個元素 -->
<!-- 1. 通過ref屬性綁定被遍歷元素 -->
<!-- 2. 通過this.$refs.li 獲取所有遍歷元素 -->
<!-- <ul>
<li v-for="i in 4" :key="i" ref="li">{{i}}</li>
</ul> -->
<!-- 單個元素 -->
<div ref="dom">我是box</div>
<!-- 被遍歷的元素 -->
<ul>
<li v-for="i in 4" :key="i" :ref="setDom">第{{i}}LI</li>
</ul>
</div>
</template>
<script>
import { onMounted, ref } from 'vue'
export default {
name: 'App',
setup () {
// 1. 獲取單個元素
// 1.1 先定義一個空的響應式數據ref定義的
// 1.2 setup中返回該數據萄唇,你想獲取那個dom元素檩帐,在該元素上使用ref屬性綁定該數據即可。
const dom = ref(null)
onMounted(()=>{
console.log(dom.value)
})
}
}
</script>
<style scoped lang="less"></style>
獲取v-for遍歷的DOM或者組件:
// 2. 獲取v-for遍歷的元素
// 2.1 定義一個空數組另萤,接收所有的LI
// 2.2 定義一個函數湃密,往空數組push DOM
const domList = []
const setDom = (el) => {
domList.push(el)
}
onMounted(()=>{
console.log(domList)
})
return {dom, setDom}
總結:
單個元素:先申明ref響應式數據,返回給模版使用四敞,通過ref綁定數據
-
遍歷的元素:先定義一個空數組泛源,定一個函數獲取元素,返回給模版使用忿危,通過ref綁定這個函數
- 有一個邊界問題:組件更新的時候會重復的設置dom元素給數組:
// ref獲取v-for遍歷的DOM元素达箍,需要在組件更新的時候重置接受dom元素的數組。 onBeforeUpdate(()=>{ list = [] })
4.4 父子通訊
父傳子:
子傳父:
總結:
- 父傳子:在setup種使用props數據
setup(props){ // props就是父組件數據 }
- 子傳父:觸發(fā)自定義事件的時候emit來自
setup(props,{emit}){ // emit 就是觸發(fā)事件函數 }
- 在vue3.0中
v-model
和.sync
已經合并成v-model
指令
4.5 依賴注入(祖孫通訊)
- 使用provide函數和inject函數完成后代組件數據通訊
總結:
- provide函數提供數據和函數給后代組件使用
- inject函數給當前組件注入provide提供的數據和函數
五铺厨、補充
5.1 v-model語法糖
- 在vue2.0中v-mode語法糖簡寫的代碼
<Son :value="msg" @input="msg=$event" />
- 在vue3.0中v-model語法糖有所調整:
<Son :modelValue="msg" @update:modelValue="msg=$event" />
演示代碼:
//父組件App
<template>
<div class="container">
<!-- 如果你想獲取原生事件事件對象 -->
<!-- 如果綁定事函數 fn fn(e){ // e 就是事件對象 } -->
<!-- 如果綁定的是js表達式 此時提供一個默認的變量 $event -->
<h1 @click="$event.target.style.color='red'">父組件 {{count}}</h1>
<hr>
<!-- 如果你想獲取自定義事件 -->
<!-- 如果綁定事函數 fn fn(data){ // data 觸發(fā)自定義事件的傳參 } -->
<!-- 如果綁定的是js表達式 此時 $event代表觸發(fā)自定義事件的傳參 -->
<!-- <Son :modelValue="count" @update:modelValue="count=$event" /> -->
<Son v-model="count" />
</div>
</template>
<script>
import { ref } from 'vue'
import Son from './Son.vue'
export default {
name: 'App',
components: {
Son
},
setup () {
const count = ref(10)
return { count }
}
}
</script>
//子組件Son
<template>
<div class="container">
<h2>子組件 {{modelValue}} <button @click="fn">改變數據</button></h2>
</div>
</template>
<script>
export default {
name: 'Son',
props: {
modelValue: {
type: Number,
default: 0
}
},
setup (props, {emit}) {
const fn = () => {
// 改變數據
emit('update:modelValue', 100)
}
return { fn }
}
}
</script>
總結: vue3.0封裝組件支持v-model的時候缎玫,父傳子:modelValue
子傳父 @update:modelValue
補充: vue2.0的 xxx.sync
語法糖解析 父傳子 :xxx
子傳父 @update:xxx
在vue3.0 使用 v-model:xxx
代替。
5.2 mixins語法
- 混入 (mixin) 提供了一種非常靈活的方式解滓,來分發(fā) Vue 組件中的可復用功能赃磨。一個混入對象可以包含任意組件選項。當組件使用混入對象時洼裤,所有混入對象的選項將被“混合”進入該組件本身的選項邻辉。
理解全局混入:所有組件混入了這些邏輯代碼
總結: 在vue2.0中一些可復用的邏輯可以使用mixins來封裝,當是需要考慮邏輯代碼沖突問題。vue3.0的組合API很好的解決了這個問題恩沛,就不在推薦使用mixins了在扰。