昨天完成了表單常用的文字輸入框,感覺表單好像結束了呢!? 等等…還沒完呢! (我還有 25 天)
想想一個表單有一個以上的欄位要填寫,且有些欄位內容是固定的,如果需要使用者按照規定的格式填寫,難保會出現各種奇奇怪怪的寫法(x)
所以除了可以讓使用者自由輸入的輸入框以外,常見的還有下拉式選單 (select) ,下拉式選單能有效的提供使用者可用的選項,給予引導的效果,且在有大量資料需要呈現的情況下能讓畫面保持整潔喔~
一樣先思考 select 需要哪些狀態呢? 🤔
label跟 placeholder 提示使用者輸入disabled 不可選取狀態<option>選項可選與不可選狀態簡單介紹到這邊,讓我們開始實作吧!
開始實作會發現…喔不!  標籤並沒有像  標籤提供 placeholder 這個 attribute,別擔心我們可以把第一個 option 借來當作 placeholder 用用…
<script lang="ts" setup>
export interface SelectPropsType {
  /** 預設內容文字 */
  placeholder?: string
  /** 標籤 */
  label?: string
  /** 標籤樣式 */
  classLabel?: string
  /** 輸入框樣式 */
  classInput?: string
  /** label for => select id */
  name: string
  /** v-modal */
  modelValue: any
  /** 錯誤訊息 */
  error?: string
  /** 是否不可選 */
  disabled?: boolean
  /** 是否複選 */
  multiple?: boolean
  /** 選項型別 */
  options: Array<{
    value: string
    label: string
    disabled?: boolean
  }>
}
withDefaults(defineProps<SelectPropsType>(), {
  label: '',
  classLabel: '',
  classInput: '',
  name: '',
  modelValue: '',
  error: '',
  description: '',
  size: '',
  options: () => [
    {
      value: '',
      label: 'Select Option'
    },
    {
      value: '',
      label: 'Select Option2'
    }
  ]
})
defineEmits(['update:modelValue'])
</script>
<template>
  <div
    class="fromGroup relative items-center"
    :class="{'has-error': error}"
  >
    <label
      class="input-label"
      :for="name"
    >
      <span :class="classLabel">{{ label }}</span>
    </label>
    <div
      class="relative"
    >
      <select
        v-bind="$attrs"
        :id="name"
        :name="name"
        :class="`${classInput} input-control`"
        :value="modelValue"
        :error="error"
        :disabled="disabled"
        :multiple="multiple"
        @input="$emit('update:modelValue', ($event.target as HTMLInputElement).value)"
      >
        <option
          v-if="placeholder"
          value=""
          selected
        >
          {{ placeholder }}
        </option>
          <option
            v-for="(item, index) in options"
            :key="index"
            :value="item.value"
            :disabled="item.disabled"
          >
            {{ item.label }}
          </option>
      </select>
    </div>
    <span
      v-if="error"
      class="absolute -bottom-6 right-0 mt-2  text-red-500 block text-sm"
    >{{ error }}</span>
  </div>
</template>
<style>
select {
  @apply ...
}
option {
  @apply ...
}
</style>
defineModel,可以試試看把它改成 defineModel 的模式呦完成之後的樣子~
<script lang="ts" setup>
const selectValue = ref('')
const options = [
  {
      value: '1',
      label: '魚'
    },
    {
      value: '2',
      label: '金魚'
    },
    {
      value: '3',
      label: '大頭魚',
      disabled: true
    }
]
</script>
<template>
  <div class="flex gap-x-4">   
    <Select :options="options" placeholder="- 請選擇魚 -" />
    <Select :options="options" disabled placeholder="- 請選擇魚 -" />
    <Select :options="options" disabled placeholder="- 請選擇魚 -" error="禁止撈魚"/>
  </div>
</template>
