组件关系 ​
常用入口:通过 options 渲染完整单选集合。需要手写选项时使用 单选组 与 单选项 / 按钮单选项。
使用场景 ​
从规范化 options 渲染单选集合;独立单选项使用 RadioItem,插槽组合使用 RadioGroup。 本组件只消费静态选项。
选项与按钮形态 ​
type 切换普通或 button 形态;option 插槽接收规范化 option,选项 disabled 与整个控件 disabled 各自生效。
选项与按钮形态
<template>
<div class="example">
<AsamRadio v-model="value" :options="options" @change="event = JSON.stringify($event)">
<template #option="{ option }"> {{ option.label }}团队 </template>
</AsamRadio>
<AsamRadio v-model="value" :options="options" type="button" />
<AsamRadio :model-value="value" :options="options" disabled />
<output>值:{{ value }};change:{{ event }}</output>
</div>
</template>
<script lang="ts" setup>
defineOptions({ name: 'AsamRadioBasicExample' });
import { ref } from 'vue';
import { AsamRadio } from '@asam-ui/ui';
const options = [
{ label: '设计', value: 'design', raw: { code: 'design' } },
{ label: '开发', value: 'dev', raw: { code: 'dev' } },
{ label: '停用', value: 'off', disabled: true, raw: { code: 'off' } }
];
const value = ref<string | null>('design');
const event = ref('尚未更改');
</script>
<style scoped>
.example {
display: grid;
gap: var(--asam-space-md, 16px);
min-width: 0;
}
.row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--asam-space-sm, 8px);
}
.density-grid {
display: grid;
gap: var(--asam-space-md, 16px);
grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
}
section {
display: grid;
gap: var(--asam-space-sm, 8px);
min-width: 0;
}
output {
overflow-wrap: anywhere;
color: var(--asam-color-text-secondary);
}
</style>
<template>
<div class="example">
<AsamRadio v-model="value" :options="options" @change="event = JSON.stringify($event)">
<template #option="{ option }"> {{ option.label }}团队 </template>
</AsamRadio>
<AsamRadio v-model="value" :options="options" type="button" />
<AsamRadio :model-value="value" :options="options" disabled />
<output>值:{{ value }};change:{{ event }}</output>
</div>
</template>
<script setup>
defineOptions({ name: 'AsamRadioBasicExample' });
import { ref } from 'vue';
import { AsamRadio } from '@asam-ui/ui';
const options = [
{ label: '设计', value: 'design', raw: { code: 'design' } },
{ label: '开发', value: 'dev', raw: { code: 'dev' } },
{ label: '停用', value: 'off', disabled: true, raw: { code: 'off' } }
];
const value = ref('design');
const event = ref('尚未更改');
</script>
<style scoped>
.example {
display: grid;
gap: var(--asam-space-md, 16px);
min-width: 0;
}
.row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--asam-space-sm, 8px);
}
.density-grid {
display: grid;
gap: var(--asam-space-md, 16px);
grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
}
section {
display: grid;
gap: var(--asam-space-sm, 8px);
min-width: 0;
}
output {
overflow-wrap: anywhere;
color: var(--asam-color-text-secondary);
}
</style>
连续按钮与显式 Group 对照 ​
type="button" 的相邻按钮连续拼接,只有首尾保留外侧圆角,中间保留单条接缝。四档尺寸与显式 RadioGroup + RadioButton 一致;普通单选形态保持密度间距。禁用项仍在组内占位,Tab 聚焦当前项,方向键在可选项间移动。min/max/tag 属于多选能力,单选集合不接受这些属性。
四档连续按钮与显式 Group 对照
<template>
<div class="example">
<section v-for="size in sizes" :key="size">
<strong>{{ size }}</strong>
<AsamRadio v-model="selected" :size="size" type="button" :options="options" />
<AsamRadioGroup v-model="selected" :size="size" aria-label="插槽按钮组">
<AsamRadioButton
v-for="option in options"
:key="option.value"
:value="option.value"
:disabled="option.disabled"
>{{ option.label }}</AsamRadioButton
>
</AsamRadioGroup>
<AsamRadio v-model="selected" :size="size" :options="options" />
</section>
<output>当前值:{{ selected }}</output>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { AsamRadio, AsamRadioGroup, AsamRadioButton } from '@asam-ui/ui';
import type { AsamControlSize } from '@asam-ui/ui';
const sizes: AsamControlSize[] = ['large', 'big', 'default', 'small'];
const selected = ref('design');
const options = [
{ value: 'design', label: '设计', raw: {} },
{ value: 'develop', label: '开发', raw: {} },
{ value: 'disabled', label: '停用', disabled: true, raw: {} }
];
defineOptions({ name: 'AsamRadioContinuousDemo' });
</script>
<style scoped>
.example,
section {
display: grid;
gap: var(--asam-space-md, 16px);
}
</style>
<template>
<div class="example">
<section v-for="size in sizes" :key="size">
<strong>{{ size }}</strong>
<AsamRadio v-model="selected" :size="size" type="button" :options="options" />
<AsamRadioGroup v-model="selected" :size="size" aria-label="插槽按钮组">
<AsamRadioButton
v-for="option in options"
:key="option.value"
:value="option.value"
:disabled="option.disabled"
>{{ option.label }}</AsamRadioButton
>
</AsamRadioGroup>
<AsamRadio v-model="selected" :size="size" :options="options" />
</section>
<output>当前值:{{ selected }}</output>
</div>
</template>
<script setup>
import { ref } from 'vue';
import { AsamRadio, AsamRadioGroup, AsamRadioButton } from '@asam-ui/ui';
const sizes = ['large', 'big', 'default', 'small'];
const selected = ref('design');
const options = [
{ value: 'design', label: '设计', raw: {} },
{ value: 'develop', label: '开发', raw: {} },
{ value: 'disabled', label: '停用', disabled: true, raw: {} }
];
defineOptions({ name: 'AsamRadioContinuousDemo' });
</script>
<style scoped>
.example,
section {
display: grid;
gap: var(--asam-space-md, 16px);
}
</style>
对象值与存储策略 ​
对象模式返回完整 option;空值为 null。选项值按类型和值唯一,字符串 1 与数字 1 可以在值模式区分。
对象值与存储策略
<template>
<div class="example">
<AsamRadio v-model="objectValue" :options="options" value-mode="object" />
<output>对象:{{ objectValue }}</output>
</div>
</template>
<script lang="ts" setup>
defineOptions({ name: 'AsamRadioPoliciesExample' });
import { ref } from 'vue';
import { AsamRadio } from '@asam-ui/ui';
const options = [
{ label: '设计', value: 'design', raw: { code: 'design' } },
{ label: '开发', value: 'dev', raw: { code: 'dev' } },
{ label: '停用', value: 'off', disabled: true, raw: { code: 'off' } }
];
const objectValue = ref<(typeof options)[number] | null>(options[0]);
</script>
<style scoped>
.example {
display: grid;
gap: var(--asam-space-md, 16px);
min-width: 0;
}
.row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--asam-space-sm, 8px);
}
.density-grid {
display: grid;
gap: var(--asam-space-md, 16px);
grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
}
section {
display: grid;
gap: var(--asam-space-sm, 8px);
min-width: 0;
}
output {
overflow-wrap: anywhere;
color: var(--asam-color-text-secondary);
}
</style>
<template>
<div class="example">
<AsamRadio v-model="objectValue" :options="options" value-mode="object" />
<output>对象:{{ objectValue }}</output>
</div>
</template>
<script setup>
defineOptions({ name: 'AsamRadioPoliciesExample' });
import { ref } from 'vue';
import { AsamRadio } from '@asam-ui/ui';
const options = [
{ label: '设计', value: 'design', raw: { code: 'design' } },
{ label: '开发', value: 'dev', raw: { code: 'dev' } },
{ label: '停用', value: 'off', disabled: true, raw: { code: 'off' } }
];
const objectValue = ref(options[0]);
</script>
<style scoped>
.example {
display: grid;
gap: var(--asam-space-md, 16px);
min-width: 0;
}
.row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--asam-space-sm, 8px);
}
.density-grid {
display: grid;
gap: var(--asam-space-md, 16px);
grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
}
section {
display: grid;
gap: var(--asam-space-sm, 8px);
min-width: 0;
}
output {
overflow-wrap: anywhere;
color: var(--asam-color-text-secondary);
}
</style>
四档尺寸与上下文继承 ​
四个实例分别显式使用 large、big、default、small。下面省略 size 的实例随 ConfigProvider 响应切换;显式 size 覆盖祖先。面板本身没有 size 契约的入口不附加虚构尺寸属性。
四档尺寸与上下文继承
<template>
<div class="example">
<div class="density-grid">
<section data-density="large">
<strong> large </strong>
<AsamRadio size="large" :options="options" model-value="design" />
</section>
<section data-density="big">
<strong> big </strong>
<AsamRadio size="big" :options="options" model-value="design" />
</section>
<section data-density="default">
<strong> default </strong>
<AsamRadio size="default" :options="options" model-value="design" />
</section>
<section data-density="small">
<strong> small </strong>
<AsamRadio size="small" :options="options" model-value="design" />
</section>
</div>
<AsamConfigProvider :size="density">
<section data-density="inherited">
<AsamRadio :options="options" model-value="design" />
</section>
</AsamConfigProvider>
<div class="row">
<AsamButton type="default" @click="density = 'small'"> 继承 small </AsamButton>
<AsamButton type="default" @click="density = 'big'"> 继承 big </AsamButton>
</div>
<output>配置提供器:{{ density }}</output>
</div>
</template>
<script lang="ts" setup>
defineOptions({ name: 'AsamRadioSizesExample' });
import { ref } from 'vue';
import { AsamRadio, AsamConfigProvider, AsamButton } from '@asam-ui/ui';
import type { AsamControlSize } from '@asam-ui/ui';
const density = ref<AsamControlSize>('big');
const options = [
{ label: '设计', value: 'design', raw: { code: 'design' } },
{ label: '开发', value: 'dev', raw: { code: 'dev' } },
{ label: '停用', value: 'off', disabled: true, raw: { code: 'off' } }
];
</script>
<style scoped>
.example {
display: grid;
gap: var(--asam-space-md, 16px);
min-width: 0;
}
.row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--asam-space-sm, 8px);
}
.density-grid {
display: grid;
gap: var(--asam-space-md, 16px);
grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
}
section {
display: grid;
gap: var(--asam-space-sm, 8px);
min-width: 0;
}
output {
overflow-wrap: anywhere;
color: var(--asam-color-text-secondary);
}
</style>
<template>
<div class="example">
<div class="density-grid">
<section data-density="large">
<strong> large </strong>
<AsamRadio size="large" :options="options" model-value="design" />
</section>
<section data-density="big">
<strong> big </strong>
<AsamRadio size="big" :options="options" model-value="design" />
</section>
<section data-density="default">
<strong> default </strong>
<AsamRadio size="default" :options="options" model-value="design" />
</section>
<section data-density="small">
<strong> small </strong>
<AsamRadio size="small" :options="options" model-value="design" />
</section>
</div>
<AsamConfigProvider :size="density">
<section data-density="inherited">
<AsamRadio :options="options" model-value="design" />
</section>
</AsamConfigProvider>
<div class="row">
<AsamButton type="default" @click="density = 'small'"> 继承 small </AsamButton>
<AsamButton type="default" @click="density = 'big'"> 继承 big </AsamButton>
</div>
<output>配置提供器:{{ density }}</output>
</div>
</template>
<script setup>
defineOptions({ name: 'AsamRadioSizesExample' });
import { ref } from 'vue';
import { AsamRadio, AsamConfigProvider, AsamButton } from '@asam-ui/ui';
const density = ref('big');
const options = [
{ label: '设计', value: 'design', raw: { code: 'design' } },
{ label: '开发', value: 'dev', raw: { code: 'dev' } },
{ label: '停用', value: 'off', disabled: true, raw: { code: 'off' } }
];
</script>
<style scoped>
.example {
display: grid;
gap: var(--asam-space-md, 16px);
min-width: 0;
}
.row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--asam-space-sm, 8px);
}
.density-grid {
display: grid;
gap: var(--asam-space-md, 16px);
grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
}
section {
display: grid;
gap: var(--asam-space-sm, 8px);
min-width: 0;
}
output {
overflow-wrap: anywhere;
color: var(--asam-color-text-secondary);
}
</style>
ASAM 扩展与迁移 ​
ASAM 将集合组件与独立 Item/Group 分开。 完整说明。
default 插槽有可渲染内容时使用自定义子项;内容为空时回到 options 自动渲染。动态切换插槽内容保持外部模型的值模式。
默认插槽与空内容回退
<template>
<div class="example">
<AsamButton type="default" @click="custom = !custom">切换默认插槽</AsamButton>
<AsamRadio v-model="value" :options="options">
<template #default>
<template v-if="custom">
<AsamRadioItem
v-for="option in options"
:key="option.value"
:value="option.value"
>
自定义{{ option.label }}
</AsamRadioItem>
</template>
</template>
</AsamRadio>
<AsamRadio
v-model="objectValue"
:options="options"
v-bind="{ valueMode: 'object', type: 'button' }"
>
<template #default>
<template v-if="custom">
<AsamRadioButton
v-for="option in options"
:key="option.value"
:value="option.value"
>
自定义{{ option.label }}
</AsamRadioButton>
</template>
</template>
</AsamRadio>
<output>{{ JSON.stringify({ custom, value, objectValue }) }}</output>
</div>
</template>
<script lang="ts" setup>
defineOptions({ name: 'AsamRadioDefaultSlotExample' });
import { ref } from 'vue';
import { AsamButton, AsamRadio, AsamRadioItem, AsamRadioButton } from '@asam-ui/ui';
const options = [
{ value: 'design', label: '设计', raw: { code: 'design' } },
{ value: 'dev', label: '开发', raw: { code: 'dev' } }
];
const custom = ref(true);
const value = ref('design');
const objectValue = ref<(typeof options)[number] | null>(options[0]);
</script>
<style scoped>
.example {
display: grid;
gap: var(--asam-space-md, 16px);
}
</style>
<template>
<div class="example">
<AsamButton type="default" @click="custom = !custom">切换默认插槽</AsamButton>
<AsamRadio v-model="value" :options="options">
<template #default>
<template v-if="custom">
<AsamRadioItem
v-for="option in options"
:key="option.value"
:value="option.value"
>
自定义{{ option.label }}
</AsamRadioItem>
</template>
</template>
</AsamRadio>
<AsamRadio
v-model="objectValue"
:options="options"
v-bind="{ valueMode: 'object', type: 'button' }"
>
<template #default>
<template v-if="custom">
<AsamRadioButton
v-for="option in options"
:key="option.value"
:value="option.value"
>
自定义{{ option.label }}
</AsamRadioButton>
</template>
</template>
</AsamRadio>
<output>{{ JSON.stringify({ custom, value, objectValue }) }}</output>
</div>
</template>
<script setup>
defineOptions({ name: 'AsamRadioDefaultSlotExample' });
import { ref } from 'vue';
import { AsamButton, AsamRadio, AsamRadioItem, AsamRadioButton } from '@asam-ui/ui';
const options = [
{ value: 'design', label: '设计', raw: { code: 'design' } },
{ value: 'dev', label: '开发', raw: { code: 'dev' } }
];
const custom = ref(true);
const value = ref('design');
const objectValue = ref(options[0]);
</script>
<style scoped>
.example {
display: grid;
gap: var(--asam-space-md, 16px);
}
</style>
事件与实例 ​
update:modelValue(value):按已配置值模式更新当前模型。change(value):用户改变选择,模型归一化后返回。
两者的 value 参数均为 AsamValue、AsamChoiceOption<AsamValue, object> 或 null,实际分支由 valueMode 决定。 完整说明。
API 阅读方式 ​
API 按公开类型与运行默认值生成;未知默认值不等于 false 或空值。 完整说明。
集合与基础控件的定位 ​
本入口是 options + Group 的 ASAM 聚合,保留规范化对象/值模型,不作为单个原生控件的替代。 完整说明。
API
属性 AsamRadioProps
| 属性名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
options | — | readonly AsamChoiceOption<V, I>[] | undefined | () => [] |
disabled | 是否禁用单选框 | boolean | undefined | undefined |
name | 原生 name 属性 | string | undefined | undefined |
id | — | string | undefined | undefined |
validateEvent | — | boolean | undefined | true |
size | 单选框按钮或边框按钮的大小 | enum"large" | "big" | "default" | "small"完整类型:AsamControlSize | undefined | undefined |
ariaLabel | — | string | undefined | — |
fill | — | string | undefined | "" |
textColor | — | string | undefined | "" |
type | — | enum"button" | "radio"完整类型:"button" | "radio" | undefined | "radio" |
modelValue | 选中项绑定值 | V | null | undefined | AsamChoiceOption<V, I> | null | undefined | — |
valueMode | — | enum"value" | "object"完整类型:"value" | undefined | "object" | 'value' |
插槽 AsamRadioSlots
| 属性名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
default | — | (() => unknown) | undefined | — |
option | — | ((scope: { option: AsamChoiceOption<AsamValue, object>; }) => unknown) | undefined | — |
用法与契约补充说明 ​
ASAM 扩展与迁移 ​
ASAM 将集合组件与独立 Item/Group 分开。四档尺寸在组内继承;规范化 options 必须含 raw。旧接口不能混用对象与字符串模型。default 插槽覆盖自动选项渲染,option 插槽仅自定义单项。公开事件为 update:modelValue 与 change,当前集合没有公开 expose。数据请求使用 Remote/Dict 组件。
事件与实例 ​
两者的 value 参数均为 AsamValue、AsamChoiceOption<AsamValue, object> 或 null,实际分支由 valueMode 决定。单选不接收 multipleValueMode、separator 或多选的 min/max/tag;运行时显式拒绝这些已移除字段。原始选项字段映射 props 由 AsamRadioGroup 承接,集合只消费规范化 options。当前没有公开实例方法。事件元组直接来自集合 SFC 的真实声明;集合没有命名 Emits 类型可供自动投影。
API 阅读方式 ​
下方 Props、Events、Slots、Exposes 按当前实际公开类型与运行默认值生成。组合属性按分支生效,不能任意混搭值模式。标为“未知 / 未声明”的默认值不代表 false 或空值。源码区域提供对应语言的独立 Demo.vue,可直接复制或下载;本地辅助组件、数据和素材已内联到当前文件。此集合的 update:modelValue 与 change 在组件源码内声明;没有公开命名 Emits 类型和 expose,事件返回值与上述模型模式一致。
集合与基础控件的定位 ​
本入口是 options + Group 的 ASAM 聚合,保留规范化对象/值模型,不作为单个原生控件的替代。原生公开 props/events/slots 使用对应 Item、Group、Button 入口。type="button" 将选项连续拼接,四档尺寸的首项、中项、尾项保留原生边框、圆角、选中和禁用交互;组内 gap 为 0,普通非 button 仍使用 ASAM 间距。焦点与键盘交给原生 Group/子项,不自建导航。
关联组件
参数与事件补充说明
组合 Options 与 Group;基础输入使用独立的 Item、Group、Button 入口。
组合契约按分支生效;请同时查看公开类型。
参数与事件说明
options
必填:否;声明来源:ASAM 声明。
默认值与来源
() => [](源码表达式;ASAM 声明)disabled
必填:否;声明来源:ASAM 声明。
disabled 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
undefined(已安装运行时;已安装组件)name
必填:否;声明来源:ASAM 声明。
默认值与来源
undefined(源码表达式;ASAM 声明)id
必填:否;声明来源:ASAM 声明。
默认值与来源
undefined(源码表达式;ASAM 声明)validateEvent
必填:否;声明来源:ASAM 声明。
validateEvent 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
true(已安装运行时;已安装组件)size
必填:否;声明来源:ASAM 声明。
size 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:"large" / "big" / "default" / "small"
默认值与来源
undefined(源码表达式;ASAM 声明)ariaLabel
必填:否;声明来源:上游声明。
fill
必填:否;声明来源:上游声明。
默认值与来源
""(已安装运行时;已安装组件)固定上游源码默认表达式:''(2.14.7;源码事实,未作为 ASAM 运行实测)
textColor
必填:否;声明来源:上游声明。
默认值与来源
""(已安装运行时;已安装组件)固定上游源码默认表达式:''(2.14.7;源码事实,未作为 ASAM 运行实测)
type
必填:否;声明来源:ASAM 声明。
type 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:"button" / "radio"
默认值与来源
"radio"(已安装运行时;已安装组件)modelValue
必填:否;声明来源:ASAM 声明。
modelValue 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
modelValue.label:string— 数据 / provider 协议modelValue.value:V— 数据 / provider 协议modelValue.disabled:boolean | undefined— 数据 / provider 协议枚举:
false/truemodelValue.raw:I— 数据 / provider 协议modelValue.children:readonly AsamOption<V, I>[] | undefined— 数据 / provider 协议
valueMode
必填:否;声明来源:ASAM 声明。
valueMode 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:"value"
枚举:"object"
默认值与来源
'value'(源码表达式;ASAM 声明)AsamRadioProps 公开类型视图
import type { AsamRadioProps, AsamValue, AsamRecord, AsamChoiceOption, AsamChoiceRuntimeProps, AsamControlSize, AsamOption } from '@asam-ui/ui';
type PublicMember<T, K extends PropertyKey> = T extends unknown ? K extends keyof T ? T[K] : never : never;
// AsamRadioProps
type PublicContract<V extends AsamValue = AsamValue, I extends object = AsamRecord> = AsamRadioProps<V, I>;
基础 Group 处理原始选项字段映射;ASAM 组合组件保留规范化选项。
参数与事件说明
default
必填:否;声明来源:ASAM 声明。
default 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): unknown
option
必填:否;声明来源:ASAM 声明。
option 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(scope: { option: AsamChoiceOption<AsamValue, object>; }): unknown
AsamRadioSlots 公开类型视图
import type { AsamRadioSlots, AsamValue, AsamChoiceOption } from '@asam-ui/ui';
// AsamRadioSlots
type PublicContract = {
"default"?: (() => unknown) | undefined;
"option"?: ((scope: { option: AsamChoiceOption<AsamValue, object>; }) => unknown) | undefined;
};