iT邦幫忙

2024 iThome 鐵人賽

DAY 7
0
Modern Web

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

元件製作 radio

  • 分享至 

  • xImage
  •  

radio 跟昨天的 checkbox 很相像,但使用情境結果大不同!
複習一下,checkbox 在面對單選時回傳的是 truefalse,一個以上的選項會變成複選的狀態。

但如果遇到一個必須回傳值的單選題(比如便當主餐只能選一個,不考慮雙主餐的情況)時,就會變得不好操作了~

這時候就能體現 radio 的優勢了,他能將選項的值回傳,且只可以選一個選項,後續也通常會搭配提交按鈕進行下一步。

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

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

實作

  • 注意 name 的欄位,賦予同一個值的話代表他們是同一題呦
  • 在這邊我一樣將 <input> 包在 <label> 裡面,如此就不需要使用 id 和 for 來進行連動

<script lang="ts" setup>
export interface RadioPropsType {
  /** 標籤 */
  label?: string
  /** 預設是否勾選 */
  checked?: boolean
  /** 是否禁用 */
  disabled?: boolean
  /** name 標籤(group 使用) */
  name?: string
  /** input 選項代表的值 */
  value?: any
  /** 響應式值 */
  modelValue?: any
}

const props = withDefaults(defineProps<RadioPropsType>(), {
  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="radio"
        class="hidden"
        :disabled="disabled"
        :name="name"
        :value="value"
        @change="onChange"
      >

      <span
        :class="
          localValue === value
            ? 'ring-primary-600 border-primary-600 ring-[6px] ring-inset ring-offset-2'
            : 'border-slate-400'
        "
        class="relative inline-flex size-[18px] rounded-full border bg-white transition-all duration-150 mr-3"
      />
      <span
        v-if="label"
        class="text-sm leading-6 text-slate-500"
      >
        {{ label }}
      </span>
    </label>
  </div>
</template>
  • 最後呈現~
<script setup lang="ts">
const picked1 = ref('A')
const picked2 = ref('C')

const option = ref('ORANGE')
const options = [
  {
    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>Radio 狀態</h3>
      <div class="flex flex-wrap gap-4">
        <Radio
          v-model="picked1"
          label="Checked"
          class="mb-5"
          name="x"
          value="A"
        />
        <Radio
          v-model="picked1"
          label="UnChecked"
          :checked="true"
          class="mb-5"
          name="x"
          value="B"
        />
        <Radio
          v-model="picked2"
          label="Checked disabled"
          disabled
          class="mb-5"
          name="x2"
          value="C"
        />
        <Radio
          v-model="picked2"
          label="UnChecked disabled"
          name="x2"
          disabled
          class="mb-5"
          value="D"
        />
      </div>
    </div>
    <div class="flex flex-col text-xl gap-4 mb-4">
      <h3>Radio 選取</h3>
      <div
          v-for="(item, i) in options"
          :key="i"
        >
          <Radio
            v-model="option"
            :label="item.label"
            class="mb-"
            name="jorina"
            :value="item.value"
          />
        </div>

        <div class="mt-3 text-slate-900 dark:text-slate-300">
          Selected: {{ option }}
        </div>
    </div>
  </div>
</template>

image.png


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

尚未有邦友留言

立即登入留言