Skip to content

单选框 Radio ​

赞助

在一组备选项中选中单个状态,支持圆点、按钮与配置式写法,选中值由 RadioGroup 统一维护

何时使用 ​

  • 用于在多个备选项中选中单个状态
  • 和 Select 的区别是,Radio 所有选项默认可见,方便用户在比较中选择,因此选项不宜过多
  • 需要统一维护一组选项的选中值时,使用 RadioGroup 包裹一组 Radio

基本使用 ​

独立用法:v-model:checked 双向绑定选中态,change 事件回传最新选中值


Show Code
vue
<script setup lang="ts">
import { ref } from 'vue'
const checked = ref<boolean>(false)
const onChange = (value: boolean) => {
  console.log('change', value)
}
</script>
<template>
  <Radio v-model:checked="checked" @change="onChange">Radio</Radio>
</template>

单选组合 ​

选中值由 RadioGroup 统一维护,组内 Radio 用 value 标识自身,无需各自维护选中态


Show Code
vue
<script setup lang="ts">
import { ref } from 'vue'
import type { RadioProps } from 'vue-amazing-ui'
const groupItems = [
  { value: 1, label: 'A' },
  { value: 2, label: 'B' },
  { value: 3, label: 'C' },
  { value: 4, label: 'D' }
]
const value = ref<RadioProps['value']>(1)
</script>
<template>
  <RadioGroup v-model:value="value">
    <Radio v-for="item in groupItems" :key="item.value" :value="item.value">{{ item.label }}</Radio>
  </RadioGroup>
</template>

表单字段名 ​

设置 name 后,组内各原生 input 共享同一字段名,浏览器据此把它们识别为同一组选项


Show Code
vue
<script setup lang="ts">
import { ref } from 'vue'
const nameItems = [
  { value: '1', label: 'A' },
  { value: '2', label: 'B' },
  { value: '3', label: 'C' },
  { value: '4', label: 'D' }
]
const value = ref<string>('1')
</script>
<template>
  <RadioGroup v-model:value="value" name="radioGroup">
    <Radio v-for="item in nameItems" :key="item.value" :value="item.value">{{ item.label }}</Radio>
  </RadioGroup>
</template>

选项列表 ​

配置式写法:传入 options 数组即可渲染整组选项;自定义选项名、按钮形态等能力均由 RadioGroup 承载


Show Code
vue
<script setup lang="ts">
import { ref } from 'vue'
import type { RadioGroupOption, RadioProps } from 'vue-amazing-ui'
const options = ref<RadioGroupOption[]>([
  { label: '拜占庭', value: 1 },
  { label: '君士坦丁堡', value: 2 },
  { label: '伊斯坦布尔', value: 3 },
  { label: '布宜诺斯艾利斯', value: 4 }
])
const value = ref<RadioProps['value']>(1)
</script>
<template>
  <RadioGroup v-model:value="value" :options="options" />
</template>

单选组垂直排列 ​

选项内需要放输入框等控件时,逐项定高并居中,可避免控件出现 / 消失时整行跳动


Show Code
vue
<script setup lang="ts">
import { ref } from 'vue'
import type { RadioProps } from 'vue-amazing-ui'
const items = [
  { value: 1, label: 'Option A' },
  { value: 2, label: 'Option B' },
  { value: 3, label: 'Option C' },
  { value: 4, label: 'More...' }
]
const verticalStyle: Record<string, string> = {
  display: 'flex',
  alignItems: 'center',
  height: '32px',
  lineHeight: '30px'
}
const value = ref<RadioProps['value']>(1)
</script>
<template>
  <RadioGroup v-model:value="value" style="display: inline-block">
    <Radio v-for="item in items" :key="item.value" :value="item.value" :style="verticalStyle">
      {{ item.label }}
      <Input v-if="item.value === 4 && value === 4" style="width: 100px; margin-left: 10px" />
    </Radio>
  </RadioGroup>
</template>

也可以直接用 vertical 让组内选项垂直排列


Show Code
vue
<script setup lang="ts">
import { ref } from 'vue'
import type { RadioProps } from 'vue-amazing-ui'
const groupItems = [
  { value: 1, label: 'A' },
  { value: 2, label: 'B' },
  { value: 3, label: 'C' },
  { value: 4, label: 'D' }
]
const value = ref<RadioProps['value']>(1)
</script>
<template>
  <RadioGroup v-model:value="value" vertical>
    <Radio v-for="item in groupItems" :key="item.value" :value="item.value">{{ item.label }}</Radio>
  </RadioGroup>
</template>

按钮样式 ​

按钮形态有两种写法:组内放 RadioButton,或给组设置 button


默认
单项禁用
整组禁用
配置式
Show Code
vue
<script setup lang="ts">
import { ref } from 'vue'
import type { RadioGroupOption, RadioProps } from 'vue-amazing-ui'
const buttonItems = [
  { value: 'a', label: 'Hangzhou' },
  { value: 'b', label: 'Shanghai' },
  { value: 'c', label: 'Beijing' },
  { value: 'd', label: 'Chengdu' }
]
const options = ref<RadioGroupOption[]>([
  { label: '拜占庭', value: 1 },
  { label: '君士坦丁堡', value: 2 },
  { label: '伊斯坦布尔', value: 3 },
  { label: '布宜诺斯艾利斯', value: 4 }
])
const value = ref<RadioProps['value']>('a')
const itemDisabledValue = ref<RadioProps['value']>('a')
const groupDisabledValue = ref<RadioProps['value']>('a')
</script>
<template>
  <RadioGroup v-model:value="value">
    <RadioButton v-for="button in buttonItems" :key="button.value" :value="button.value">
      {{ button.label }}
    </RadioButton>
  </RadioGroup>
  <RadioGroup v-model:value="itemDisabledValue">
    <RadioButton
      v-for="button in buttonItems"
      :key="button.value"
      :value="button.value"
      :disabled="button.value === 'b'"
    >
      {{ button.label }}
    </RadioButton>
  </RadioGroup>
  <RadioGroup v-model:value="groupDisabledValue" disabled>
    <RadioButton v-for="button in buttonItems" :key="button.value" :value="button.value">
      {{ button.label }}
    </RadioButton>
  </RadioGroup>
  <RadioGroup v-model:value="value" :options="options" button />
</template>

单组件同样可用 button 切换按钮形态


Show Code
vue
<script setup lang="ts">
import { ref } from 'vue'
const checked = ref<boolean>(false)
</script>
<template>
  <Radio v-model:checked="checked" button>Radio Button</Radio>
</template>

填底的按钮样式 ​

在按钮形态基础上设置 buttonStyle="solid",选中项以主题色填底


默认
单项禁用
配置式
Show Code
vue
<script setup lang="ts">
import { ref } from 'vue'
import type { RadioGroupOption, RadioProps } from 'vue-amazing-ui'
const buttonItems = [
  { value: 'a', label: 'Hangzhou' },
  { value: 'b', label: 'Shanghai' },
  { value: 'c', label: 'Beijing' },
  { value: 'd', label: 'Chengdu' }
]
const options = ref<RadioGroupOption[]>([
  { label: '拜占庭', value: 1 },
  { label: '君士坦丁堡', value: 2 },
  { label: '伊斯坦布尔', value: 3 },
  { label: '布宜诺斯艾利斯', value: 4 }
])
const value = ref<RadioProps['value']>('a')
const itemDisabledValue = ref<RadioProps['value']>('a')
</script>
<template>
  <RadioGroup v-model:value="value" button-style="solid">
    <RadioButton v-for="button in buttonItems" :key="button.value" :value="button.value">
      {{ button.label }}
    </RadioButton>
  </RadioGroup>
  <RadioGroup v-model:value="itemDisabledValue" button-style="solid">
    <RadioButton v-for="button in buttonItems" :key="button.value" :value="button.value" :disabled="button.value === 'b'">
      {{ button.label }}
    </RadioButton>
  </RadioGroup>
  <RadioGroup v-model:value="value" :options="options" button button-style="solid" />
</template>

单组件的填底按钮形态:button 配合 buttonStyle="solid"


Show Code
vue
<script setup lang="ts">
import { ref } from 'vue'
const checked = ref<boolean>(false)
</script>
<template>
  <Radio v-model:checked="checked" button button-style="solid">Radio Button Solid</Radio>
</template>

按钮大小 ​

组的 size 统一作用于组内所有按钮,未指定时各按钮回落自身 size


large
middle
small
Show Code
vue
<script setup lang="ts">
import { ref } from 'vue'
import type { RadioProps } from 'vue-amazing-ui'
const buttonItems = [
  { value: 'a', label: 'Hangzhou' },
  { value: 'b', label: 'Shanghai' },
  { value: 'c', label: 'Beijing' },
  { value: 'd', label: 'Chengdu' }
]
const value = ref<RadioProps['value']>('a')
const middleValue = ref<RadioProps['value']>('a')
const smallValue = ref<RadioProps['value']>('a')
</script>
<template>
  <RadioGroup v-model:value="value" size="large">
    <RadioButton v-for="button in buttonItems" :key="button.value" :value="button.value">
      {{ button.label }}
    </RadioButton>
  </RadioGroup>
  <RadioGroup v-model:value="middleValue" size="middle">
    <RadioButton v-for="button in buttonItems" :key="button.value" :value="button.value">
      {{ button.label }}
    </RadioButton>
  </RadioGroup>
  <RadioGroup v-model:value="smallValue" size="small">
    <RadioButton v-for="button in buttonItems" :key="button.value" :value="button.value">
      {{ button.label }}
    </RadioButton>
  </RadioGroup>
</template>

单组件按自身 size 渲染,可与上方的尺寸选择联动切换


尺寸
单组件
配置式
Show Code
vue
<script setup lang="ts">
import { ref } from 'vue'
import type { RadioGroupOption, RadioProps } from 'vue-amazing-ui'
const options = ref<RadioGroupOption[]>([
  { label: '拜占庭', value: 1 },
  { label: '君士坦丁堡', value: 2 },
  { label: '伊斯坦布尔', value: 3 },
  { label: '布宜诺斯艾利斯', value: 4 }
])
const sizeOptions = [
  { label: 'small', value: 'small' },
  { label: 'middle', value: 'middle' },
  { label: 'large', value: 'large' }
]
const buttonSizeValue = ref<RadioProps['size']>('middle')
const checked = ref<boolean>(false)
const value = ref<RadioProps['value']>(2)
</script>
<template>
  <RadioGroup :options="sizeOptions" v-model:value="buttonSizeValue" button button-style="solid" />
  <Radio v-model:checked="checked" button :size="buttonSizeValue">Radio Button</Radio>
  <RadioGroup :options="options" v-model:value="value" button :size="buttonSizeValue" />
</template>

禁用 ​

开关演示整组禁用:禁用后不可聚焦、不可切换,disabled 由组统一下发给组内各项


Toggle disabled
单选按钮
配置式
按钮形态
单选组
Show Code
vue
<script setup lang="ts">
import { ref } from 'vue'
import type { RadioGroupOption, RadioProps } from 'vue-amazing-ui'
const options = ref<RadioGroupOption[]>([
  { label: '拜占庭', value: 1 },
  { label: '君士坦丁堡', value: 2 },
  { label: '伊斯坦布尔', value: 3 },
  { label: '布宜诺斯艾利斯', value: 4 }
])
const disabled = ref<boolean>(true)
const checked1 = ref<boolean>(true)
const checked2 = ref<boolean>(false)
const optionsValue = ref<RadioProps['value']>(1)
const buttonValue = ref<RadioProps['value']>(1)
const groupValue = ref<RadioProps['value']>(1)
const toggleDisabled = () => {
  disabled.value = !disabled.value
}
</script>
<template>
  <Button type="primary" @click="toggleDisabled">Toggle disabled</Button>
  <Radio v-model:checked="checked1" :disabled="disabled">Disabled</Radio>
  <Radio v-model:checked="checked2" :disabled="disabled">Disabled</Radio>
  <RadioGroup :options="options" v-model:value="optionsValue" disabled />
  <RadioGroup :options="options" v-model:value="buttonValue" button disabled />
  <RadioGroup v-model:value="groupValue" :options="options" disabled />
</template>

禁用选项 ​

在选项数据里给单项设置 disabled: true,仅该项不可选,其余选项不受影响


单选组
按钮形态
Show Code
vue
<script setup lang="ts">
import { ref } from 'vue'
import type { RadioGroupOption, RadioProps } from 'vue-amazing-ui'
const options = ref<RadioGroupOption[]>([
  { label: '拜占庭', value: 1 },
  { label: '君士坦丁堡', value: 2, disabled: true },
  { label: '伊斯坦布尔', value: 3 },
  { label: '布宜诺斯艾利斯', value: 4 }
])
const value = ref<RadioProps['value']>(1)
const buttonValue = ref<RadioProps['value']>(1)
</script>
<template>
  <RadioGroup v-model:value="value" :options="options" />
  <RadioGroup v-model:value="buttonValue" :options="options" button />
</template>

自定义选项名 ​

options 模式的默认插槽提供 option / label / index,可自行渲染选项名


插槽 · 配置式
插槽 · 组合式
Show Code
vue
<script setup lang="ts">
import { ref } from 'vue'
import type { RadioGroupOption, RadioProps } from 'vue-amazing-ui'
const options = ref<RadioGroupOption[]>([
  { label: '拜占庭', value: 1 },
  { label: '君士坦丁堡', value: 2 },
  { label: '伊斯坦布尔', value: 3 },
  { label: '布宜诺斯艾利斯', value: 4 }
])
const value = ref<RadioProps['value']>(2)
const groupValue = ref<RadioProps['value']>(2)
</script>
<template>
  <RadioGroup :options="options" v-model:value="value">
    <template #default="{ option, label, index }">
      <span v-if="index === 1" style="color: #ff6900">{{ label }}</span>
      <span v-else-if="index === 3" style="color: #1677ff">{{ option?.label }}</span>
      <span v-else>{{ label }}</span>
    </template>
  </RadioGroup>
  <RadioGroup v-model:value="groupValue">
    <Radio :value="1">拜占庭</Radio>
    <Radio :value="2"><span style="color: #ff6900">君士坦丁堡</span></Radio>
    <Radio :value="3">伊斯坦布尔</Radio>
    <Radio :value="4"><span style="color: #1677ff">布宜诺斯艾利斯</span></Radio>
  </RadioGroup>
</template>

选项名支持富内容:配置式可把 VNode 作为 label 传入,组合式直接在插槽内写 HTML 或组件


VNode · 配置式
VNode · 组合式
Show Code
vue
<script setup lang="ts">
import { h, ref } from 'vue'
import type { RadioGroupOption, RadioProps } from 'vue-amazing-ui'
const vnodeOptions: RadioGroupOption[] = [
  { label: '拜占庭', value: 1 },
  { label: h('span', { style: 'color: #ff6900' }, '君士坦丁堡'), value: 2 },
  { label: '伊斯坦布尔', value: 3 }
]
const value = ref<RadioProps['value']>(1)
const groupValue = ref<RadioProps['value']>(1)
</script>
<template>
  <RadioGroup :options="vnodeOptions" v-model:value="value" />
  <RadioGroup v-model:value="groupValue">
    <Radio :value="1">拜占庭</Radio>
    <Radio :value="2"><span style="color: #1677ff">君士坦丁堡</span></Radio>
    <Radio :value="3">伊斯坦布尔</Radio>
  </RadioGroup>
</template>

自定义间距 ​

gap 传数组时为「水平间距, 垂直间距」;垂直间距仅在选项换行时才生效,此处用窄容器触发换行


水平间距 16px
16
垂直间距 8px
8
窄容器
Show Code
vue
<script setup lang="ts">
import { ref } from 'vue'
import type { RadioGroupOption, RadioProps } from 'vue-amazing-ui'
const options = ref<RadioGroupOption[]>([
  { label: '拜占庭', value: 1 },
  { label: '君士坦丁堡', value: 2 },
  { label: '伊斯坦布尔', value: 3 },
  { label: '布宜诺斯艾利斯', value: 4 }
])
const horizontalGap = ref(16)
const verticalGap = ref(8)
const value = ref<RadioProps['value']>(2)
</script>
<template>
  <Flex gap="small" vertical>
    <span>水平间距 {{ horizontalGap }}px</span>
    <Slider v-model:value="horizontalGap" :width="200" />
  </Flex>
  <Flex gap="small" vertical>
    <span>垂直间距 {{ verticalGap }}px</span>
    <Slider v-model:value="verticalGap" :width="200" />
  </Flex>
  <!-- 容器宽度不足时选项换行,此时垂直间距生效 -->
  <div style="width: 240px">
    <RadioGroup :gap="[horizontalGap, verticalGap]" :options="options" v-model:value="value" />
  </div>
</template>

单选组间距 ​

组的 gap 传数字即统一间距;打开「垂直排列」后 gap 转为行间距


选项间距 16px
16
垂直排列
Show Code
vue
<script setup lang="ts">
import { ref } from 'vue'
import type { RadioProps } from 'vue-amazing-ui'
const groupItems = [
  { value: 1, label: 'A' },
  { value: 2, label: 'B' },
  { value: 3, label: 'C' },
  { value: 4, label: 'D' }
]
const groupGap = ref(16)
const groupVertical = ref<boolean>(true)
const value = ref<RadioProps['value']>(1)
</script>
<template>
  <Flex gap="small" vertical>
    <span>选项间距 {{ groupGap }}px</span>
    <Slider v-model:value="groupGap" :width="200" />
  </Flex>
  <Flex gap="small" vertical align="flex-start">
    <span>垂直排列</span>
    <Switch v-model:value="groupVertical" />
  </Flex>
  <RadioGroup v-model:value="value" :gap="groupGap" :vertical="groupVertical">
    <Radio v-for="item in groupItems" :key="item.value" :value="item.value">{{ item.label }}</Radio>
  </RadioGroup>
</template>

聚焦方法 ​

组件暴露 focus / blur 方法操作原生 input,程序化聚焦同样会显示焦点环;键盘聚焦与脚本聚焦显示焦点环,鼠标按下不显示


圆点形态
focus
blur
未聚焦

按钮形态
focus
blur
未聚焦
Show Code
vue
<script setup lang="ts">
import { ref } from 'vue'
import type { Radio, RadioButton } from 'vue-amazing-ui'
const checked = ref<boolean>(false)
const focused = ref<boolean>(false)
const radioRef = ref<InstanceType<typeof Radio> | null>(null)
const buttonChecked = ref<boolean>(false)
const buttonFocused = ref<boolean>(false)
const buttonRef = ref<InstanceType<typeof RadioButton> | null>(null)
</script>
<template>
  <Flex vertical gap="small" align="start">
    <span class="demo-label">圆点形态</span>
    <Flex gap="small" align="center">
      <Radio ref="radioRef" v-model:checked="checked" @focusin="focused = true" @focusout="focused = false">Radio</Radio>
      <Button @click="radioRef?.focus()">focus</Button>
      <Button @click="radioRef?.blur()">blur</Button>
      <span>{{ focused ? '已聚焦' : '未聚焦' }}</span>
    </Flex>
  </Flex>
  <Flex vertical gap="small" align="start">
    <span class="demo-label">按钮形态</span>
    <Flex gap="small" align="center">
      <RadioButton
        ref="buttonRef"
        v-model:checked="buttonChecked"
        @focusin="buttonFocused = true"
        @focusout="buttonFocused = false"
      >
        Radio Button
      </RadioButton>
      <Button @click="buttonRef?.focus()">focus</Button>
      <Button @click="buttonRef?.blur()">blur</Button>
      <span>{{ buttonFocused ? '已聚焦' : '未聚焦' }}</span>
    </Flex>
  </Flex>
</template>

APIs ​

Radio Props ​

名称说明类型默认值
checked
v-model
当前是否选中;作为组内单项使用时以组的值为准,本属性不生效booleanfalse
value本项的值;脱离组时随 change 事件回传,置于 RadioGroup 内时作为本项的身份标识,与组内当前值比较得出选中态string | number | booleanundefined
button是否启用按钮样式;置于 RadioGroup 内时,组为按钮形态同样按按钮渲染(本属性为 true 时优先)booleanfalse
buttonStyle按钮样式风格;置于 RadioGroup 内时以组的配置为准'outline' | 'solid''outline'
size尺寸,仅当按钮形态时生效;置于 RadioGroup 内时以组的配置为准,组未指定时回落自身尺寸'small' | 'middle' | 'large''middle'
disabled是否禁用booleanfalse
autofocus是否自动聚焦原生 inputbooleanfalse
name原生 input 的表单字段名;置于 RadioGroup 内时以组的配置为准stringundefined
id原生 input 的 idstringundefined

RadioGroup Props ​

受控 / 非受控:传入 v-model:value 即受控,组件只经 update:value 上报;不传时由组自持,可用 defaultValue 指定初值。两者同时传时以 value 为准。

名称说明类型默认值
value
v-model
组内当前选中的值;传入即受控,不传时由组自持(可用 defaultValue 指定初值)string | number | booleanundefined
defaultValue非受控初始值,未绑 v-model:value 时生效string | number | booleanundefined
options单选框选项数据;提供后组内默认插槽不生效(string | number | RadioGroupOption)[][]
button是否启用按钮样式booleanfalse
buttonStyle按钮形态的风格,仅按钮形态生效'outline' | 'solid''outline'
size尺寸,仅作用于按钮形态;未指定时组内各项回落自身尺寸'small' | 'middle' | 'large'undefined
vertical是否垂直排列;按钮形态(组的 button 或组内 RadioButton)不适用booleanfalse
gap选项间距,单位 px;垂直排列时即垂直间距(传数组取垂直间距);数组用于水平排列折行时:[水平间距, 垂直间距];按钮形态下相邻项贴合成组,该属性不生效number | number[]8
disabled是否禁用整组,组内单项自身的 disabled 在此基础上叠加booleanfalse
name表单字段名,下发到组内每个原生 inputstringundefined
idinput 的 id 前缀,options 模式下实际 id 追加选项下标;组合式用法不下发,请在组内各项上自行设置stringundefined
autofocus是否自动聚焦首项,仅 options 模式生效booleanfalse

RadioButton Props ​

名称说明类型默认值
checked
v-model
脱离组单独使用时的选中态booleanfalse
value该项的值,置于组内时据此判断选中string | number | booleanundefined
disabled是否禁用booleanfalse
autofocus是否自动聚焦原生 inputbooleanfalse
name原生 input 的表单字段名;置于 RadioGroup 内时以组的配置为准stringundefined
id原生 input 的 idstringundefined

RadioGroupOption Type ​

名称说明类型
label?选项名,未提供时以选项值展示;传入 VNode 时原样渲染string | number | VNode
value选项值string | number | boolean
disabled?是否禁用选项boolean

Slots ​

Radio Slots ​

名称说明用法
default选项名v-slot:default

RadioGroup Slots ​

名称说明用法
defaultoptions 模式下为每个选项提供作用域参数;未提供 options 时用于放置 Radio / RadioButtonv-slot:default="{ option, label, index }"

RadioButton Slots ​

名称说明用法
default按钮文本v-slot:default

Events ​

Radio Events ​

名称说明类型
change选项变化时的回调函数;脱组单独使用时触发(仅未选中 → 选中,首参恒为 true),作为 RadioGroup 的组内单项使用时本组件不触发(组内选中变更由组的 change 统一出口)(checked: boolean, event: RadioChangeEvent) => void

event 为与原生 input 的 change 同形态的事件对象,含 target(checked / value / name / disabled 状态快照)、nativeEvent 与 stopPropagation / preventDefault

RadioGroup Events ​

名称说明类型
change组内选项变化时的回调函数(value: string | number | boolean, event: RadioChangeEvent) => void

event.target.checked 恒为 true(选中事件),value 为本次选中的值,name / disabled 取该项当前生效的字段名与禁用态。

RadioButton Events ​

名称说明类型
change选项变化时的回调函数;脱离组单独使用时触发,置于 RadioGroup 内时不触发(组内选中变更由 RadioGroup 的 change 统一出口)(checked: boolean, event: RadioChangeEvent) => void

Methods ​

Radio Methods ​

名称说明类型
focus聚焦组件的原生 input() => void
blur使组件的原生 input 失焦() => void

RadioButton Methods ​

名称说明类型
focus聚焦组件的原生 input() => void
blur使组件的原生 input 失焦() => void

Released under the MIT License.