高級 Vue 組件模式 (2)
- 2020 年 1 月 21 日
- 筆記
02 編寫複合組件
目標
我們需要實現的需求是能夠使使用者通過 <toggle>
組件動態地改變包含在它內部的內容。
熟悉 vue 的童鞋可能馬上會想到不同的解決方案,比如使用 slot
並配合 v-if
,我們這裡採用另外一種方法,利用 vue 提供的 provide/inject
屬性按照複合組件的思想來實現。
這裡簡單介紹下 provide/inject
的功能,它允許某個父組件向子組件注入一個依賴項(這裡的父子關係可以跨域多個層級,也就是祖先與後代),如果我們在其他 mvvm 框架對比來看的話,你可以發現其他框架也具有相同的特性,比如:
- angularjs: directive 中的
require
屬性來聲明注入邏輯 - Angular: 依賴注入中組件級別的注入器
- React: context 上下文對象
想進一步了解的話,可以參考官方文檔
實現
在 vue 中,這裡我們會分別實現三個組件,依次為:
toggle-button
: 代表開關,用來渲染父組件的開關狀態toggle-on
: 根據父組件 toggle 的開關狀態,渲染當狀態為開時的內容toggle-off
: 根據父組件 toggle 的開關狀態,渲染當狀態為關時的內容
在上一篇文章中,我們已經實現了 toggle 組件,這裡我們要做一些更改。首先,需要使用 provide 屬性增加一個提供依賴的邏輯,如下:
provide() { return { toggleComp: { status: this.status, toggle: this.toggle } } }
這裡的 status 是該組件 data 中的聲明的一個可監聽對象,這個對象包含一個 on 屬性來代表組件的開關狀態,而 toggle 則是 methods 中的一個組件方法。
關於為什麼這裡不直接使用 on 屬性來代表開關狀態,而使用一個可監聽對象,是因為 provide
和 inject
綁定並不是可響應的,同時官方文檔也指出,這是刻意而為,所以為了享受到 vue 響應性帶來的便利性,我們這裡傳入 status 這個可監聽對象。
對於其他三個組件,其內部實現邏輯十分簡單,相信讀者通過參考在線程式碼實例馬上就能看懂,這裡只提一下關於 inject
聲明注入依賴的邏輯,如下:
inject: { toggleComp: "toggleComp" }
這裡的 "toggleComp"
與之前的 provide 對象中聲明的 key 值所對應,而 inject 對象的 key 值當前組件注入依賴項的變數名稱,之後,子組件即可以通過 this.toggleComp
來訪問父組件的屬性與方法。
成果
通過複合組件的方式,我們將 toggle
組件劃分為了三個更小的、職責更加單一的子組件。同時由於 toggle-on
和 toggle-off
都使用 slot 來動態地注入組件調用者在其內部包含的自定義渲染邏輯,其靈活性得到了進一步的提升,只要這三個組件是作為 toggle
組件的子組件來調用,一切都將正常運行。
你可以通過下面的鏈接來看看這個組件的實現程式碼以及演示:
總結
通常情況下,在設計和實現職能分明的組件時,可以使用這種模式,比如 tabs 與 tab 組件,tabs 只負責 tab 的滾動、導航等邏輯,而 tab 本身僅負責內容的渲染,就如同這裡的 toggle 和 toggle-button、toggle-on、toggle-off 一樣。