開關(切換)

開關是一種在兩個狀態之間切換值的友善介面,並提供與原生核取方塊元素相同的語意和鍵盤導覽功能。

首先,透過 npm 安裝 Headless UI。

請注意,這個函式庫僅支援 Vue 3

npm install @headlessui/vue

開關是使用 Switch 元件建構的,這個元件會透過 v-model 屬性接收 ref。您可以直接按一下元件或在焦點時按下空白鍵進行開關切換。

切換開關時您的 ref 會更新為否定的值。

<template> <Switch v-model="enabled" :class="enabled ? 'bg-blue-600' : 'bg-gray-200'" class="relative inline-flex h-6 w-11 items-center rounded-full" > <span class="sr-only">Enable notifications</span> <span :class="enabled ? 'translate-x-6' : 'translate-x-1'" class="inline-block h-4 w-4 transform rounded-full bg-white transition" /> </Switch> </template> <script setup> import { ref } from 'vue' import { Switch } from '@headlessui/vue' const enabled = ref(false) </script>

Headless UI 記錄了元件的許多狀態,例如目前選取哪個開關選項、浮動選單是否開啟或關閉,或選單中哪個項目目前由鍵盤控制。

但由於這些元件是無頭的且完全不具備樣式,因此您必須自行提供每種狀態所需的樣式,才能在 UI 中「看見」此資訊。

每個元件會透過 插槽屬性公開其目前狀態的資訊,您可以使用這些屬性有條件地套用不同的樣式或呈現不同的內容。

例如,Switch 元件會公開一個 checked 狀態,這會告訴您開關目前是否已勾選。

<template>
<!-- Use the `checked` state to conditionally style the button. -->
<Switch v-model="enabled" as="template" v-slot="{ checked }"> <button class="relative inline-flex h-6 w-11 items-center rounded-full"
:class="checked ? 'bg-blue-600' : 'bg-gray-200'"
>
<span class="sr-only">Enable notifications</span> <span
:class="checked ? 'translate-x-6' : 'translate-x-1'"
class="inline-block h-4 w-4 transform rounded-full bg-white transition" />
</button> </Switch> </template> <script setup> import { ref } from 'vue' import { Switch } from '@headlessui/vue' const enabled = ref(false) </script>

如需所有可用插槽屬性的完整清單,請參閱 元件 API 文件

每個元件也會揭露關於其目前的狀態的資訊,透過一個 data-headlessui-state 屬性,你可以使用它有條件套用不同樣式。

當在 插槽屬性 API 裡的任何狀態為 true,它們會在這個屬性中列出為以空格分隔的字串,因此你可以用 CSS 屬性選取器 的樣式 [attr~=value] 來鎖定它們。

例如,以下是 Switch 元件在切換開關開啟時會呈現的狀態

<!-- Rendered `Switch` --> <button data-headlessui-state="checked"></button>

如果你正在使用 Tailwind CSS,你可以使用 @headlessui/tailwindcss 外掛來鎖定這個屬性,具有像是 ui-checked:* 的修改詞。

<template> <Switch v-model="enabled"
class="relative inline-flex h-6 w-11 items-center rounded-full ui-checked:bg-blue-600 ui-not-checked:bg-gray-200"
>
<span class="sr-only">Enable notifications</span> <span
class="inline-block h-4 w-4 transform rounded-full bg-white transition ui-checked:translate-x-6 ui-not-checked:translate-x-1"
/>
</Switch> </template> <script setup> import { ref } from 'vue' import { Switch } from '@headlessui/vue' const enabled = ref(false) </script>

預設情況下,切換開關會呈現一個 button,以及你傳入的任何子元素。這可能會讓人更難實作某些 UI,因為元件的子元素會巢狀在按鈕內。

在這些情況下,你可以使用 SwitchLabel 元件來獲得更好的彈性。

這個範例說明如何使用 SwitchGroupSwitchSwitchLabel 元件來呈現一個與按鈕為兄弟元素的標籤。請注意 SwitchLabel 元件必須與 Switch 元件搭配使用,且它們都必須呈現於 SwitchGroup 父元素元件內。

<template>
<SwitchGroup>
<div class="flex items-center">
<SwitchLabel class="mr-4">Enable notifications</SwitchLabel>
<Switch v-model="enabled" :class='enabled ? "bg-blue-600" : "bg-gray-200"' class="relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2" > <span :class='enabled ? "translate-x-6" : "translate-x-1"' class="inline-block h-4 w-4 transform rounded-full bg-white transition-transform" /> </Switch> </div>
</SwitchGroup>
</template> <script setup> import { ref } from 'vue' import { Switch, SwitchGroup, SwitchLabel } from '@headlessui/vue' const enabled = ref(false) </script>

預設情況下,點擊 SwitchLabel 會切換切換開關,就像原生 HTML 核取方塊的標籤一樣。如果你想要讓這個標籤不可點擊(如果你覺得它不適合你的設計,你可能會這麼做),你可以將 passive 屬性新增至 SwitchLabel 元件

<template> <SwitchGroup>
<SwitchLabel passive>Enable notifications</SwitchLabel>
<Switch v-model="enabled"> <!-- ... --> </Switch> </SwitchGroup> </template> <script setup> import { ref } from 'vue' import { Switch, SwitchGroup, SwitchLabel } from '@headlessui/vue' const enabled = ref(false) </script>

如果你在切換開關新增 name 屬性,一個隱藏的 input 元素將會呈現並保持與切換開關狀態同步。

<template> <form action="/notification-settings" method="post">
<Switch v-model="enabled" name="notifications">
<!-- ... --> </Switch> </form> </template> <script setup> import { ref } from 'vue' import { Switch } from '@headlessui/vue' const enabled = ref(true) </script>

這讓你可以在原生 HTML <form> 內使用一個切換開關,並進行傳統的表單提交,就好像你的切換開關是一個原生 HTML 表單控制元件一樣。

預設情況下,當切換開關開啟時,數值將會是 'on',當切換開關關閉時,數值則不會存在。

<input type="hidden" name="notifications" value="on" />

如果你需要,你可以透過使用 value 屬性自訂數值。

<template> <form action="/accounts" method="post">
<Switch v-model="enabled" name="terms" value="accept">
<!-- ... --> </Switch> </form> </template> <script setup> import { ref } from 'vue' import { Switch } from '@headlessui/vue' const enabled = ref(true) </script>

當切換開關開啟時,隱藏的輸入元件將會使用你自訂的數值

<input type="hidden" name="terms" value="accept" />

如果你針對 Switch 提供 defaultChecked 道具,而不是 checked 道具,Headless UI 會為你內部追蹤其狀態,如此一來你便能以 不受控元件 的形式使用它。

透過 Switch 元件上的 checked 槽道具,你可以存取目前的狀態。

<template> <form action="/accounts" method="post"> <Switch name="terms-of-service"
:defaultChecked="true"
as="template" v-slot="{ checked }" >
<button :class="checked ? 'bg-blue-600' : 'bg-gray-200'" class="relative inline-flex h-6 w-11 items-center rounded-full" > <span class="sr-only">Enable notifications</span> <span :class="checked ? 'translate-x-6' : 'translate-x-1'" class="inline-block h-4 w-4 transform rounded-full bg-white transition" /> </button> </Switch> <button>Submit</button> </form> </template> <script setup> import { Switch } from '@headlessui/vue' </script>

當將列表方塊 與 HTML 表單一併使用,或是要使用表格 API(這些 API 是利用 FormData 來收集其狀態,而不是使用 React 狀態來追蹤)時,此舉可以簡化你的程式碼。

你提供的任何 @update:modelValue 道具仍會在元件的值變更時被呼叫,萬一你需要執行任何副作用時,不過你不需要使用它來自己追蹤元件的狀態。

由於 Switch 通常總是會呈現在 DOM 中(與其他元件被掛載/解除掛載不同),因此簡單的 CSS 轉場動畫便足以用來為你的 Switch 加入動畫效果。

<template> <Switch v-model="enabled"> <!-- Transition the switch's knob on state change --> <span
:class="enabled ? 'translate-x-9' : 'translate-x-0'"
class="transform transition duration-200 ease-in-out" />
<!-- ... --> </Switch> </template> <script setup> import { ref } from 'vue' import { Switch } from '@headlessui/vue' const enabled = ref(false) </script>

預設情況下,Switch 的子代會被用作螢幕閱讀器的標籤。如果你正在使用 SwitchLabel,你的 Switch 元件的內容會被輔助技術所忽略。

點擊 SwitchSwitchLabel 會切換 Switch 的開或關。

指令說明

SpaceSwitch 獲得焦點時

切換 Switch

Enter 當在表單中時

提交表單

所有相關的 ARIA 屬性都由系統自動管理。

主要的切換開關元件。

屬性預設值說明
asbutton
字串 | 元件

Switch 應該要呈式的元素或元件。

v-model
布林值

切換開關是否為開啟狀態。

defaultChecked
T

使用非受控元件時的預設開啟值。

name
字串

在此元件於表格中使用時使用的名稱。

value
字串

在表格中使用此元件時,若元件已開啟,將會使用的值。

插槽屬性說明
checked

布林值

切換開關是否為開啟狀態。

屬性預設值說明
aslabel
字串 | 元件

SwitchLabel 應該要呈式的元素或元件。

passivefalse
布林值

為 true 時,點擊標籤不會切換 Switch

屬性預設值說明
asp
字串 | 元件

Switch.Description 應該要呈式的元素或元件。

屬性預設值說明
astemplate
字串 | 元件

SwitchGroup 應該要呈式的元素或元件。

如果您有興趣使用 Headless UI 和 Tailwind CSS 的預先設計元件範例,請查看 Tailwind UI,這個系列由我們打造,內含設計精美、製作精良的元件。

這樣可以大幅支持我們在像這樣開源專案中的工作,同時讓我們能夠改善專案並做好維護。