iT邦幫忙

2024 iThome 鐵人賽

DAY 6
0
Modern Web

蓋一個自己的 Nuxt 3 UI Module系列 第 6

元件製作 checkbox

  • 分享至 

  • xImage
  •  

在填寫表單時也常會看到勾選框,使用者可以明確的看到每個選項,並透過一個點擊的簡單操作就能改變選取狀態,選取完後不會立即執行動作,需要搭配按鈕進行提交(可以讓使用者多想一下)

一樣先思考 checkbox 有哪些狀態 🤔

  1. 未選取
  2. 已選取
  3. disabled 禁止選取

特別要注意的就是 <input type="checkbox"> 時是可以分成單選——用來詢問是某同意網站隱私條款或是多選——問剉冰要加幾種配料等等的情況 🍧

  1. 單選
    1. 回傳 true / false: 將變數預設空值或填入 boolean,並將其與 v-model 綁訂,ckeckbox 此時無須給予 value 值,元件將回傳 true / false。當填入 true 為勾選,反之 false 為取消勾選。
    2. 回傳單一值:將變數預設空值,並將其與 v-model 綁訂,ckeckbox 此時必須給予 value 值,元件將回傳 checkbox 代表的 value 值。變數內預先填入 checkbox 的 value 值可以產生預先勾選效果。
  2. 多選 (回傳陣列): 將變數填入陣列,同一組 checkbox 的 v-model 綁定同一個變數。陣列內預先填入 checkbox 的 value 值可以產生預先勾選效果。

實作

  • 注意 name 的欄位,賦予同一個值的話代表他們是同一組呦
  • 在這邊我將 <input> 包在 <label> 裡面,如此即便不使用 idfor 也能進行連動
<script lang="ts" setup>

export interface CheckboxPropsType {
  /** 標籤 */
  label?: string
  /** 預設是否勾選 */
  checked?: boolean
  /** 是否禁用 */
  disabled?: boolean
  /** name 標籤(group 使用) */
  name?: string
  /** input 選項代表的值 */
  value?: any
  /** 響應式值,如果傳入為 array 則為多選 */
  modelValue?: any
}

const props = withDefaults(defineProps<CheckboxPropsType>(), {
  label: '',
  name: '',
  value: '',
  modelValue: ''
})

type EmitsEvent = (e: 'update:modelValue', value: any) => void

const emits = defineEmits<EmitsEvent>()
const ck = ref(props.checked)
const onChange = (): void => {
  ck.value = !ck.value
}
const localValue = computed({
  get: () => props.modelValue,
  set: (newValue) => emits('update:modelValue', newValue)
})
</script>

<template>
  <div>
    <label
      class="flex items-center"
      :class="disabled ? ' cursor-not-allowed opacity-50' : 'cursor-pointer'"
    >
      <input
        v-model="localValue"
        type="checkbox"
        class="hidden"
        :disabled="disabled"
        :name="name"
        :value="value"
        @change="onChange"
      >
      <span
        class="relative inline-flex size-4 flex-none rounded border border-primary-500 transition-all duration-150 mr-3"
        :class="
          ck
            ? 'ring-primary-500 bg-primary-600 ring-2 ring-offset-2'
            : 'bg-white'
        "
      >
        <Icon
          v-if="ck"
          name="lucide:check"
          size="14"
          class="m-auto block text-white"
        />
      </span>
      <span
        v-if="label"
        class="text-sm leading-6 text-slate-500"
      >
        {{ label }}
      </span>
    </label>
  </div>
</template>

  • 最後出來的效果是這樣~

    <script lang="ts" setup>
    const option2 = ref(['Orange'])
    const options = ref([
      {
        value: 'Orange',
        label: 'Orange'
      },
      {
        value: 'Apple',
        label: 'Apple'
      },
      {
        value: 'Banana',
        label: 'Banana'
      }
    ])
    </script>
    <template>
      <div class="relative">
        <div class="flex flex-col text-xl gap-4 mb-4">
          <h3>Checkbox 狀態</h3>
          <div class="flex flex-wrap gap-4">
            <Checkbox
            label="Checked"
            checked
            />
            <Checkbox
            label="UnChecked"
            />
            <Checkbox
            label="Checked disabled"
            disabled
            />
            <Checkbox
            label="UnChecked disabled"
            checked
            disabled
            />
          </div>
        </div>
        <div class="flex flex-col text-xl gap-4">
          <h3>Checkbox 多選</h3>
          <div class="flex flex-wrap gap-4 items-center">
            <div
                v-for="(item, i) in options"
                :key="i"
              >
                <Checkbox
                  v-model="option2"
                  :label="item.label"
                  name="group"
                  :value="item.value"
                  :checked="option2.includes(item.value)"
                />
            </div>
            <div class="text-slate-900">
              Selected: {{ option2 }}
            </div>
          </div>
        </div>
      </div>
    </template>
    


上一篇
元件製作 select
下一篇
元件製作 radio
系列文
蓋一個自己的 Nuxt 3 UI Module30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言