组件/Radio 单选框
自 1.0.0BETA

Radio 单选框

用于单选场景(`TxRadioGroup` + `TxRadio`)。支持三种形式:**标准单选**(圆点+文案)、**卡片单选**(强调信息层级)和**按钮组**(紧凑排列)。

该页面由 AI 迁移生成,请谨慎使用

内容已迁移完成,但仍建议结合源码和人工评审结果使用。

Radio 单选框

用于单选场景(TxRadioGroup + TxRadio)。支持三种形式:标准单选(圆点+文案)、卡片单选(强调信息层级)和按钮组(紧凑排列)。

标准单选形式

前圆点+后文案的标准单选形式,适合选项较多的场景。

Radio (standard)

示例即将加载...
<script setup lang="ts">
import { ref } from 'vue'

const value = ref<'a' | 'b' | 'c'>('a')
</script>

<template>
  <div class="tx-demo tx-demo__col tx-demo--max-400">
    <TxRadioGroup v-model="value" type="standard" direction="row">
      <TxRadio value="a" label="Option A" />
      <TxRadio value="b" label="Option B" />
      <TxRadio value="c" label="Option C" />
    </TxRadioGroup>

    <TxCard variant="plain" background="mask" :padding="10" :radius="14">
      <div class="tx-demo__meta">
        selected: {{ value }}
      </div>
    </TxCard>
  </div>
</template>

卡片单选形式

更强调信息层级的单选形式,适合需要解释文本的场景。

Radio (card)

示例即将加载...
<script setup lang="ts">
import { ref } from 'vue'

const value = ref<'a' | 'b' | 'c'>('a')
</script>

<template>
  <div class="tx-demo tx-demo__col tx-demo--max-520">
    <TxRadioGroup v-model="value" type="card">
      <TxRadio value="a">
        <div class="tx-demo__title">
          Option A
        </div>
        <div class="tx-demo__desc">
          Description text for option A
        </div>
      </TxRadio>
      <TxRadio value="b">
        <div class="tx-demo__title">
          Option B
        </div>
        <div class="tx-demo__desc">
          A longer description line to test wrapping and spacing
        </div>
      </TxRadio>
      <TxRadio value="c" disabled>
        <div class="tx-demo__title">
          Option C (disabled)
        </div>
        <div class="tx-demo__desc">
          Disabled option
        </div>
      </TxRadio>
    </TxRadioGroup>

    <TxCard variant="plain" background="mask" :padding="10" :radius="14">
      <div class="tx-demo__meta">
        selected: {{ value }}
      </div>
    </TxCard>
  </div>
</template>

按钮组形式

紧凑排列的按钮组,适合选项较少的场景。

Radio (simple)

示例即将加载...
<script setup lang="ts">
import { ref } from 'vue'

const value = ref<'a' | 'b' | 'c'>('a')
</script>

<template>
  <div class="tx-demo tx-demo__col">
    <TxRadioGroup v-model="value">
      <TxRadio value="a">
        Option A
      </TxRadio>
      <TxRadio value="b">
        Option B
      </TxRadio>
      <TxRadio value="c">
        Option C
      </TxRadio>
    </TxRadioGroup>

    <TxCard variant="plain" background="mask" :padding="10" :radius="14">
      <div class="tx-demo__meta">
        selected: {{ value }}
      </div>
    </TxCard>
  </div>
</template>

Indicator 动效

带指示器的按钮组动效示例:默认 → 普通 → 模糊 → 玻璃。

Radio (indicator)

示例即将加载...
<script setup lang="ts">
import { ref } from 'vue'

const valueDefault = ref<'a' | 'b' | 'c'>('a')
const valuePlain = ref<'a' | 'b' | 'c'>('a')
const valueBlur = ref<'a' | 'b' | 'c'>('a')
const valueGlass = ref<'a' | 'b' | 'c'>('a')
</script>

<template>
  <div class="tx-demo tx-demo__col tx-demo__col--18">
    <div class="tx-demo__col tx-demo__col--10">
      <div class="tx-demo__label">
        Default
      </div>
      <TxRadioGroup v-model="valueDefault">
        <TxRadio value="a">
          Option A
        </TxRadio>
        <TxRadio value="b">
          Option B
        </TxRadio>
        <TxRadio value="c">
          Option C
        </TxRadio>
      </TxRadioGroup>
    </div>

    <div class="tx-demo__col tx-demo__col--10">
      <div class="tx-demo__label">
        Plain
      </div>
      <TxRadioGroup v-model="valuePlain" :elastic="false">
        <TxRadio value="a">
          Option A
        </TxRadio>
        <TxRadio value="b">
          Option B
        </TxRadio>
        <TxRadio value="c">
          Option C
        </TxRadio>
      </TxRadioGroup>
    </div>

    <div class="tx-demo__col tx-demo__col--10">
      <div class="tx-demo__label">
        Blur
      </div>
      <TxRadioGroup v-model="valueBlur" blur>
        <TxRadio value="a">
          Option A
        </TxRadio>
        <TxRadio value="b">
          Option B
        </TxRadio>
        <TxRadio value="c">
          Option C
        </TxRadio>
      </TxRadioGroup>
    </div>

    <div class="tx-demo__col tx-demo__col--10">
      <div class="tx-demo__label">
        Glass
      </div>
      <TxRadioGroup v-model="valueGlass" glass>
        <TxRadio value="a">
          Option A
        </TxRadio>
        <TxRadio value="b">
          Option B
        </TxRadio>
        <TxRadio value="c">
          Option C
        </TxRadio>
      </TxRadioGroup>
    </div>
  </div>
</template>

禁用状态

Radio (disabled)

示例即将加载...
<script setup lang="ts">
import { ref } from 'vue'

const value = ref<'a' | 'b'>('a')
</script>

<template>
  <div class="tx-demo tx-demo__row">
    <TxRadioGroup v-model="value" disabled>
      <TxRadio value="a">
        Disabled A
      </TxRadio>
      <TxRadio value="b">
        Disabled B
      </TxRadio>
    </TxRadioGroup>

    <TxRadioGroup v-model="value">
      <TxRadio value="a" disabled>
        Option A
      </TxRadio>
      <TxRadio value="b">
        Option B
      </TxRadio>
    </TxRadioGroup>
  </div>
</template>

Playground

TxRadioGroup 的主要属性做成可调节的控制面板,用于快速验证不同形态/参数组合。

RadioGroup (playground)

示例即将加载...
<script setup lang="ts">
import { computed, ref } from 'vue'

type GroupType = 'button' | 'standard' | 'card'

type OptionValue = 'a' | 'b' | 'c'

const type = ref<GroupType>('button')
const direction = ref<'row' | 'column'>('row')
const disabled = ref(false)

type IndicatorVariant = 'solid' | 'outline' | 'glass' | 'blur'

const indicatorVariant = ref<IndicatorVariant>('solid')

const glass = ref(false)
const blur = ref(false)
const elastic = ref(true)

const stiffness = ref(110)
const damping = ref(12)
const blurAmount = ref(1)

const value = ref<OptionValue>('a')

const shouldShowDirection = computed(() => type.value !== 'button')
const shouldShowIndicatorProps = computed(() => type.value === 'button')

const resolvedGlass = computed(() => {
  if (!shouldShowIndicatorProps.value)
    return false
  if (indicatorVariant.value === 'glass')
    return true
  return glass.value
})

const resolvedBlur = computed(() => {
  if (!shouldShowIndicatorProps.value)
    return false
  if (indicatorVariant.value === 'blur')
    return true
  return blur.value
})

const typeOptions = [
  { value: 'button', label: 'button' },
  { value: 'standard', label: 'standard' },
  { value: 'card', label: 'card' },
]

const directionOptions = [
  { value: 'row', label: 'row' },
  { value: 'column', label: 'column' },
]
</script>

<template>
  <div class="tx-demo tx-demo__col" style="max-width: 720px;">
    <TxCard variant="plain" background="mask" :padding="14" :radius="14">
      <div class="tx-demo__col" style="gap: 12px;">
        <div class="tx-demo__row">
          <label class="tx-demo__row" style="gap: 8px;">
            <span class="tx-demo__label">type</span>
            <TuffSelect v-model="type" style="min-width: 180px;">
              <TuffSelectItem v-for="opt in typeOptions" :key="opt.value" :value="opt.value" :label="opt.label" />
            </TuffSelect>
          </label>

          <label v-if="shouldShowDirection" class="tx-demo__row" style="gap: 8px;">
            <span class="tx-demo__label">direction</span>
            <TuffSelect v-model="direction" style="min-width: 180px;">
              <TuffSelectItem v-for="opt in directionOptions" :key="opt.value" :value="opt.value" :label="opt.label" />
            </TuffSelect>
          </label>
        </div>

        <div class="tx-demo__row">
          <label class="tx-demo__row" style="gap: 8px;">
            <span class="tx-demo__label">disabled</span>
            <TxSwitch v-model="disabled" />
          </label>

          <label class="tx-demo__row" style="gap: 8px;">
            <span class="tx-demo__label">elastic</span>
            <TxSwitch v-model="elastic" />
          </label>

          <label v-if="shouldShowIndicatorProps" class="tx-demo__row" style="gap: 8px;">
            <span class="tx-demo__label">indicator</span>
            <TuffSelect v-model="indicatorVariant" style="min-width: 180px;">
              <TuffSelectItem value="solid" label="solid" />
              <TuffSelectItem value="outline" label="outline" />
              <TuffSelectItem value="glass" label="glass" />
              <TuffSelectItem value="blur" label="blur" />
            </TuffSelect>
          </label>

          <label v-if="shouldShowIndicatorProps" class="tx-demo__row" style="gap: 8px;">
            <span class="tx-demo__label">blur</span>
            <TxSwitch v-model="blur" />
          </label>

          <label v-if="shouldShowIndicatorProps" class="tx-demo__row" style="gap: 8px;">
            <span class="tx-demo__label">glass</span>
            <TxSwitch v-model="glass" />
          </label>
        </div>

        <div class="tx-demo__col" style="gap: 10px;">
          <div class="tx-demo__label">
            stiffness
          </div>
          <TxSlider v-model="stiffness" :min="60" :max="220" :step="1" show-value />
        </div>

        <div class="tx-demo__col" style="gap: 10px;">
          <div class="tx-demo__label">
            damping
          </div>
          <TxSlider v-model="damping" :min="4" :max="30" :step="1" show-value />
        </div>

        <div v-if="shouldShowIndicatorProps && blur" class="tx-demo__col" style="gap: 10px;">
          <div class="tx-demo__label">
            blurAmount
          </div>
          <TxSlider v-model="blurAmount" :min="0" :max="24" :step="1" show-value />
        </div>
      </div>
    </TxCard>

    <TxCard variant="plain" background="mask" :padding="18" :radius="14" style="width: 100%;">
      <TxRadioGroup
        v-model="value"
        :type="type"
        :direction="shouldShowDirection ? direction : undefined"
        :disabled="disabled"
        :indicator-variant="shouldShowIndicatorProps ? indicatorVariant : undefined"
        :glass="resolvedGlass"
        :blur="resolvedBlur"
        :elastic="elastic"
        :stiffness="stiffness"
        :damping="damping"
        :blur-amount="blurAmount"
      >
        <TxRadio value="a" :disabled="disabled && type !== 'button'">
          <template v-if="type === 'card'">
            <div class="tx-demo__title">
              Option A
            </div>
            <div class="tx-demo__desc">
              Card description A
            </div>
          </template>
          <template v-else>
            Option A
          </template>
        </TxRadio>

        <TxRadio value="b">
          <template v-if="type === 'card'">
            <div class="tx-demo__title">
              Option B
            </div>
            <div class="tx-demo__desc">
              Card description B
            </div>
          </template>
          <template v-else>
            Option B
          </template>
        </TxRadio>

        <TxRadio value="c" :disabled="type === 'button' ? false : true">
          <template v-if="type === 'card'">
            <div class="tx-demo__title">
              Option C (disabled)
            </div>
            <div class="tx-demo__desc">
              Disabled in non-button types
            </div>
          </template>
          <template v-else>
            Option C
          </template>
        </TxRadio>
      </TxRadioGroup>

      <div class="tx-demo__meta" style="margin-top: 12px;">
        selected: {{ value }}
      </div>
    </TxCard>
  </div>
</template>

API

TxRadioGroup

Props

属性名说明类型默认值
modelValue / v-model绑定值string | number-
disabled是否禁用(整组)booleanfalse
type形态:按钮组 / 标准单选 / 卡片'button' | 'standard' | 'card''button'
direction排列方向(button 无效;standard 默认 row;card 默认 column)'row' | 'column'-
indicatorVariant指示器样式(button 有效)'solid' | 'outline' | 'glass' | 'blur'-
glass玻璃指示器(button 有效)booleanfalse
blur模糊指示器(button 有效)booleanfalse
stiffness动效刚度(越大越快)number110
damping动效阻尼(越大越稳)number12
blurAmount模糊强度(blur 有效)number1
elastic是否启用弹性形变booleantrue

Events

事件名说明回调参数
update:modelValue值更新时触发(value: string | number) => void
change值变化时触发(value: string | number) => void

Keyboard

按键行为
ArrowRight / ArrowDown选择下一个可用单选项。
ArrowLeft / ArrowUp选择上一个可用单选项。
Home / End选择第一个 / 最后一个可用单选项。

TxRadio

Props

属性名说明类型默认值
value当前项的值string | number-
label文案(无插槽时)string''
disabled是否禁用(单项)booleanfalse
type形态(一般由 group 决定)'button' | 'standard' | 'card''button'

Events

事件名说明回调参数
click点击(仅在组内变更时触发)(value: string | number) => void