iT邦幫忙

2024 iThome 鐵人賽

DAY 16
0
JavaScript

Vue.js學習中的細節陷阱:30天自我學習指南系列 第 16

Day 16: Vue的無渲染元件 - slot props 的另一種常見用法

  • 分享至 

  • xImage
  •  

在昨天寫完文章時,更加認識了Vue的slot插槽和當初不太理解的slot props用法,後來翻了一下Vue的設計模式(Vue Pattern)文章,有提到無渲染元件(renderless component),是一種需要結合slot props的另一種比較常見的應用,今天就來實作和重新理解一下吧。

今日學習目標

  1. 理解什麼是無渲染元件(renderless component)
  2. 無渲染元件Tab切換按鈕實作-另一個slot props實際應用案例

無渲染元件

無渲染元件(Renderless component)是一種 Vue的設計模式,主要概念有點像昨天結尾提到,將元件的商業互動邏輯(Logic)UI樣式展示層(View)完全分離,這樣既可以封裝功能,又不影響視覺呈現。

無渲染元件本身會專注於某些互動行為邏輯上,基本上沒有樣板(Template),而將實際的渲染交由父元件處理程式碼上通常只有共用的JS互動邏輯(script),這種模式在需要不同 UI 實現,但使用相同邏輯時特別有用,能避免重複編寫相同的邏輯代碼,實現更靈活的重用。

Tab 切換按鍵

用上次找的無渲染元件文章範例來練習吧~

像下面的Tab切換鍵有3種不一樣的UI款式,功能面上會有點擊事件和一個切換點擊的狀態:

一開始我們拿到樣式可能會習慣先開發成3種獨立元件,不過細細分析後會發現在點擊事件的互動邏輯上,這3種UI元件其實是相同的,它們其實只有template部分是不一樣的,讓我們步調放慢,一步步重構看起來有點重複性的動作。


useCheckBox - 點擊事件共用邏輯重構

首先可以將點擊事件的點選checked狀態的共用邏輯抽離變成一個組合式函式(composable),這麼一來其他元件在用到相同邏輯時就能重複利用,而不是重複地綑在Vue元件檔裡面,這樣我們的第一步checkbox UI重構就算完成。

// useCheckBox.js
import { ref } from "vue";

export function useCheckboxToggle() {
  const checkbox = ref(false); // 點擊狀態是否點擊到
  
  // 點擊互動事件
  const toggleCheckbox = () => {
    checkbox.value = !checkbox.value;
  };

  return {
    checkbox,
    toggleCheckbox,
  };
}

// 引入checkbox元件中使用

<template>
  <div class="comp">
    <label class="switch">
      <input type="checkbox" :value="checkbox" @click="toggleCheckbox" />
      <div class="slider rounded" :class="checkbox ? 'active' : ''"></div>
    </label>
  </div>
</template>

<script setup>
  import { useCheckboxToggle } from "./composables/useCheckboxToggle";

  const { checkbox, toggleCheckbox } = useCheckboxToggle();
</script>

利用 slot props 將子元件checked狀態傳送給父元件

上面有提到我們有相同的點擊邏輯,但UI樣版的樣式要3種,需要開啟給開發者做決定,其實跟上次提到的插槽slot應用很像,我們可以試著把剛剛重構程式碼變成插槽看看:

// 共用的checkbox UI元件
<template>
  <div class="comp">
   <slot></slot>  // 這裡讓父層決定template要顯示什麼
  </div>
</template>

<script setup>
  import { useCheckboxToggle } from "./composables/useCheckboxToggle";

  const { checkbox, toggleCheckbox } = useCheckboxToggle();
</script>

接著我們就要考量,如何將useCheckboxToggle的點擊狀態和互動點擊事件,透過插槽props(slots props)傳遞給父元件,並由父元件負責如何自己定義客製化樣板UI。

<template>
  // 這裡連接上子元件定義好的狀態,拋接給外層父元件使用
  <slot :checkbox="checkbox" :toggleCheckbox="toggleCheckbox"></slot>
</template>

<script setup>
  import { ref } from "vue";

  const checkbox = ref(false);

  const toggleCheckbox = () => {
    checkbox.value = !checkbox.value;
  };
</script>

父元件利用slot組裝成不同客製化UI

接著就可以統一在父層去設計不同樣式的Tab按鈕UI-範例(可以點進去參考)

<template>
  <ToggleComponent v-slot="{ checkbox, toggleCheckbox }">
    <div class="comp">
      <label class="switch">
        <input type="checkbox" :value="checkbox" @click="toggleCheckbox" />
        <div class="slider rounded" :class="checkbox ? 'active' : ''"></div>
      </label>
    </div>
  </ToggleComponent>

  <!-- Toggle element 2 -->
  <ToggleComponent v-slot="{ checkbox, toggleCheckbox }">
    <div class="comp">
      <button class="toggle-button" @click="toggleCheckbox">
        Toggle | <span>{{ checkbox ? "Yes 😀" : "No 😔" }}</span>
      </button>
    </div>
  </ToggleComponent>
</template>

<script setup>
  import ToggleComponent from "./components/ToggleComponent";
</script>

UI library 客製化樣式-slot props

其實很多工作上用到的UI元件庫,當我們需要對它進行客製化調整時也是運用同樣slot props,提供一個窗口給開發者客製化自己的UI元件,但同時保有元件庫提供的互動功能。

像是常用的PrimeVue的客製化分頁器(Paginator):

滿清楚是利用slot props 提供給使用者去接受分頁器裡包裝好的分頁狀態,開發者則可以在slot插槽內客製化自己想要的UI。


<Paginator :rows="10" :totalRecords="120" :rowsPerPageOptions="[10, 20, 30]">
    <template #start="slotProps">
        Page: {{ slotProps.state.page }}
        First: {{ slotProps.state.first }}
        Rows: {{ slotProps.state.rows }}
    </template>
    <template #end>
        <Button type="button" icon="pi pi-search" />
    </template>
</Paginator>

總結:

  • 無渲染元件是 Vue 中一種特殊的設計模式,它將互動邏輯UI顯示設計 完全分離。

https://ithelp.ithome.com.tw/upload/images/20240929/201452515ZGjL7bBNA.png

透過這種模式我們可以重用邏輯代碼和提高元件UI變化的靈活性,尤其當有相同互動邏輯需要實現不同 UI ,無渲染元件設計模式很適合呢。

slot props 能夠將一個設計好的元件的狀態與方法傳遞給父層,讓父層能自己決定具體的樣板呈現,實現客製化UI(custom UI),也是目前看到slot props比較常見的應用(相較於昨天的列表表單顯示)。

例如今天實作的 Tab 切換元件中,我們抽離了共用的點擊切換邏輯,讓每個不同的 UI 實現只需UI顯示設計上,這種設計理念同樣也出現在適用於Vue的許多UI 元件庫中。


學習資源

  1. https://www.patterns.dev/vue/renderless-components
  2. https://www.youtube.com/watch?v=2fuENUWU7Vk
  3. https://vuejs.org/guide/components/slots.html#renderless-components

上一篇
Day 15: Vue-插槽(slot)的認識、slot props的實際案例
下一篇
Day 17: Vue-非受控元件認識、列表渲染(v-for)的陷阱
系列文
Vue.js學習中的細節陷阱:30天自我學習指南30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言