關於Vue組件化的疑惑,這是Vue的缺陷嗎?

請花15秒觀察下圖,後續將對部分 UI 實現組件化:

通過分析以上UI圖,可以發現「我的家人」、「我喜愛的水果」 的UI 具有很強的相似性。

於是,我打算將這塊封裝成一個組件,名為 ItemBoard.vue(項目面板),對應圖1綠色框。這個組件可配置的地方就在於面板標題和包含的列表項。可見,傳給該組件的數據便是一個標題字元串和一個數組,我將這兩個數據作為它的props傳進來。它承擔的UI功能是遍歷展示列表項,並決定列表項間的間距,以及是否需要在列表項下面顯示一條細線。

出於靈活性考慮,我將單個列表項也封裝成了一個組件,名為 Item.vue,對應上圖的紅色框。該組件的UI可以分成左右兩部分,如上圖黑線分隔。左邊部分對於所有用例來說都是完全一樣的:頭像、名稱、描述。唯獨右邊部分有的是文字,有的是箭頭&>,有的是垃圾桶圖標。所以,該組件的右側具體顯示成什麼,應該由使用 Item 的組件來決定,即由 ItemBoard 決定。Vue 提供了 slot 語法讓父組件向子組件傳遞 UI 內容。

Item.vue UI實現大致為:

&

&…...&

&

&&

&

&

現在問題來了,ItemBoard 作為一個通用組件,它真的知道應該給 Item 的 right slot 傳什麼 UI 成分嗎?

它其實是不知道的,因為具體傳什麼 UI 成分取決於 ItemBoard 展現的是什麼數據。如果展現的是1號區塊,那麼應該根據列表數據的保單數展示文字;如果展現的是2號區塊,那麼應該全部展示右箭頭(&>)。。。

此時,似乎不得不把具體展現什麼UI的邏輯寫在 ItemBoard 中了,通過傳入的數據告訴 ItemBoard 具體展現的是幾號區塊,然後 ItemBoard 決定展現什麼 UI 給 Item。但是,這樣一來,ItemBoard 的展現就和它的數據耦合了,要是以後列表項的右側部分又多了一種 UI,那麼不得不修改 ItemBoard 的代碼以滿足新增的需求。

我對 React 也有接觸。在 React 中,這種情況很好解決,JSX語法使得將看起來像組件聲明式的組件實例作為數據放在 JS 對象中。如

{

title: 『』,

desc: 『』,

rightComponent: &

}

這樣的話,ItemBoard 只需要取傳入數據的 rightComponent 屬性便可以了。將具體展現什麼的任務交給了注入的數據,具有很大的靈活性。

所以,我的問題就是, Vue 對於這種情況應該如何處理?


Scoped Slots


補充一下,我的問題表述貌似有點不準確。如果只有圖二、圖三的話,那這就不是個問題,ItemBoard在遍歷展示item項時預留個slot,然後ItemBoard的消費者指定這個slot的 UI 就行。因為對於圖二、圖三來說,同一個列表中的所有項目右側UI都相同。但是對於圖一來說,右側需要顯示每個列表項的水果數,如果 ItemBoard 只是為圖一而設計的話,也不需要 scoped slot,因為只需要在 ItemBoard 中遍歷時讀取數據,固定顯示為 "還剩{{item.num}}只" 就行了。但是,如果 ItemBoard 的設計要同時滿足圖一、圖二、圖三通用的話,那麼就必須要將右側 UI 的展示權交給 ItemBoard 的消費者。此時,ItemBoard 的消費者在展示圖一的右側 UI 時,需要知道列表項的數據,這樣才能知道有幾隻水果。這時候 scoped slot 就派上用場了,它可以把列表項的數據反饋出來,以輔助外界提供 UI 的需要。


簡單擼了一下,如 @顧軼靈 所說的,的確可以用 scoped slot, 但還是有一點問題:

Item.vue

&

  • &
    &{{item.label}}& &

    {{item.value}}& & &
    &&
    & &

    ItemBoard.vue

    &
    &&
    & &
    &