Quasar 单选框 QRadio 组件完全指南:从基本用法到无障碍表单实战
2026/9/20 22:33:46 网站建设 项目流程
  • 前端
  • UI组件
  • 跨平台

【免费下载链接】quasar

Quasar Framework - Build high-performance VueJS user interfaces in record time

项目地址:https://gitcode.com/gh_mirrors/qu/quasar
点击查看免费下载

导读

QRadio 是 Quasar Framework 中用于"多选一"场景的基础输入组件,本文基于 radio.md 官方文档并结合仓库源码(QRadio.js、QRadio.json 及 QRadio 示例集)展开,系统讲解其 v-model 双向绑定机制、val取值原理、图标定制、颜色与尺寸控制、原生表单提交以及 v2.25+ 引入的无障碍支持。读完本文,你将能在真实项目中熟练使用 QRadio,并能在 QOptionGroup、QList 列表与原生<form>中正确落地。

[!TIP] 若需要批量创建一组单选框,建议优先参考 QOptionGroup,它能显著简化分组管理;相关组件还包括 QButtonToggle、QCheckbox 与 QToggle。

一、QRadio 是什么

QRadio 是 Quasar 中又一个基础用户输入元素,用于让用户从多个候选项中选择一个。它拥有 Material Design 风格的圆形选中指示,与 QCheckbox 的"多选"语义相对,天然表达"互斥单选"语义。

组件的完整 API 定义(props、slots、events、methods)位于 QRadio.json,其核心数据结构为:

  • model-valueAny):v-model 绑定的当前值;
  • valAny,必填):该选项对应的实际取值,选中时 v-model 会被改写为此值;
  • labelString):显示在控件旁的文案(也可用默认插槽代替);
  • 其余行为类属性:left-labelchecked-iconunchecked-iconcolorkeep-colordarkdensedisabletabindex

从源码 QRadio.js 可以看到组件 props 组合了useDarkPropsdark)、useSizePropssize)与useFormPropsnameno-error-icon等表单注入相关属性),说明 QRadio 深度集成了 Quasar 的暗色模式、尺寸体系与原生表单注入机制。

二、基础用法:v-model 与 val 的"选中即取值"

QRadio 的判断逻辑非常简单:modelValueval严格相等(===)时,该单选框处于选中状态。源码中通过toRaw对两者进行原始值比较(QRadio.js):

const isTrue = computed(() => toRaw(props.modelValue) === toRaw(props.val))

因此一组单选框只需共享同一个v-model变量,即可天然实现互斥:选中某一个时,modelValue被改写为该选项的val,其余选项因值不相等而自动取消选中。

标准用法示例(完整源码见 Standard.vue):

<template> <div class="q-pa-md"> <div class="q-gutter-sm"> <q-radio v-model="shape" val="line" label="Line" /> <q-radio v-model="shape" val="rectangle" label="Rectangle" /> <q-radio v-model="shape" val="ellipse" label="Ellipse" /> <q-radio v-model="shape" val="polygon" label="Polygon" /> </div> <div class="q-px-sm"> Your selection is: <strong>{{ shape }}</strong> </div> </div> </template> <script setup> import { ref } from 'vue' const shape = ref('line') </script>

点击行为在源码 QRadio.js 中定义:只有当组件未禁用且当前未选中时,才会触发emit('update:modelValue', props.val, e),事件同时携带原生事件对象evt(见 QRadio.json)。

[!NOTE]val可以是任意类型(字符串、数字、对象等)。但由于原生表单提交时所有值都会被转换为字符串(见下文"原生表单提交"),若需要走原生表单路径,请避免使用对象作为val

三、自定义图标:checked-icon 与 unchecked-icon

默认情况下 QRadio 使用内联 SVG 渲染圆形指示器(源码 createSvg 用两段 path 分别绘制外环与内圈对勾)。若希望换成图标,可通过checked-iconunchecked-icon指定选中/未选中状态下的 Material 图标名。

示例(完整源码见 WithIcons.vue):

<q-radio v-model="shape" checked-icon="task_alt" unchecked-icon="panorama_fish_eye" val="line" label="Line" />

源码实现中,icon计算属性会根据选中状态取对应图标(QRadio.js):

const icon = computed( () => (isTrue.value ? props.checkedIcon : props.uncheckedIcon) || null )

icon不为空时,组件改用QIcon渲染图标容器q-radio__icon-container,否则渲染默认 SVG(QRadio.js)。

四、紧凑模式:dense

在高密度界面(如列表、工具栏)中,可通过dense属性缩小单选框的垂直内边距。示例(完整源码见 Dense.vue):

<q-radio dense v-model="shape" val="line" label="Line" />

dense会为根节点追加q-radio--dense类(QRadio.js),实际间距由 QRadio.sass 中的样式规则控制。

五、颜色控制:color 与 keep-color

通过color属性可以指定选中状态的颜色(如tealorangeredcyan,值为 Quasar 调色板中的颜色名)。默认行为是仅选中时显示该颜色;若希望未选中时也保留颜色,需要同时设置keep-color

对比示例(完整源码见 Coloring.vue):

<!-- 第一行:仅选中时显示颜色 --> <q-radio v-model="color" val="teal" label="Teal" color="teal" /> <q-radio v-model="color" val="orange" label="Orange" color="orange" /> <!-- 第二行:keep-color 保留颜色(未选中也着色) --> <q-radio keep-color v-model="color" val="teal" label="Teal" color="teal" /> <q-radio keep-color v-model="color" val="orange" label="Orange" color="orange" />

源码中innerClass计算属性印证了这一逻辑(QRadio.js):

const color = props.color !== void 0 && (props.keepColor || isTrue.value) ? ` text-${props.color}` : ''

即:颜色类名text-<color>仅在「指定了 color 且(keep-color 为真或处于选中态)」时生效。

六、强制暗色模式:dark

在深色背景上使用 QRadio 时,可加dark属性强制使用暗色样式(适用于浅色页面上嵌入深色区块的场景,反之亦然)。示例(完整源码见 OnDarkBackground.vue):

<div class="q-pa-md bg-grey-9 text-white"> <q-radio dark v-model="shape" val="line" label="Line" /> <q-radio dark v-model="shape" val="rectangle" label="Rectangle" /> </div>

dark来自useDarkProps,组件通过useDark组合式函数解析最终暗色状态,选中时根节点会追加q-radio--dark类(QRadio.js)。

七、禁用状态:disable

disable属性会同时完成三件事:阻断点击(onClick中判断!props.disable)、追加disabled类、将tabindex置为-1(源码 QRadio.js),并输出aria-disabled="true"(见无障碍章节)。

示例(完整源码见 Disable.vue):

<q-radio disable v-model="shape" val="line" label="Line" />

八、标签位置:left-label

默认标签显示在控件右侧;设置left-label后标签移到左侧。可同时与dense组合使用(完整源码见 LabelPosition.vue):

<q-radio left-label v-model="shape" val="line" label="Line" /> <!-- 左侧标签 + 紧凑模式 --> <q-radio left-label dense v-model="shape" val="rectangle" label="Rectangle" />

源码中leftLabel为根节点追加reverse类实现左右翻转(QRadio.js)。

九、尺寸控制:size 与标准尺寸

除标准尺寸外,size属性支持任意自定义值(如150px2em),示例(完整源码见 StandardSizes.vue):

<q-radio size="xs" v-model="shape" val="xs" label="Size 'xs'" /> <q-radio size="sm" v-model="shape" val="sm" label="Size 'sm'" /> <q-radio size="md" v-model="shape" val="md" label="Size 'md'" /> <q-radio size="lg" v-model="shape" val="lg" label="Size 'lg'" /> <q-radio size="xl" v-model="shape" val="xl" label="Size 'xl'" /> <!-- 自定义尺寸 --> <q-radio size="150px" v-model="shape" val="150px" label="Size '150px'" />

size来自useSizeProps(见 QRadio.json 的 mixins 声明),最终通过getOptionSizeStyle工具(option-sizes.js)换算为内联样式作用于圆形控件。

十、与 QOptionGroup 配合:批量创建单选组

当需要管理大量单选项时,推荐使用 QOptionGroup,只需传入options数组并指定type="radio",即可渲染一组互斥单选框,且支持为单个选项单独设置color等属性。示例(完整源码见 OptionGroup.vue):

<template> <div class="q-pa-md"> <q-option-group :options="options" type="radio" v-model="group" /> </div> </template> <script setup> import { ref } from 'vue' const group = ref(null) const options = [ { label: 'Battery too low', value: 'bat' }, { label: 'Friend request', value: 'friend', color: 'green' }, { label: 'Picture uploaded', value: 'upload', color: 'red' } ] </script>

QOptionGroup 的完整能力(包括 disabled、dense、尺寸等透传)参见 option-group.md。

十一、与 QItem 配合:可点击的列表式单选项

在 QList 中嵌入 QRadio 时,将q-itemtag设为label,并使用v-ripple添加涟漪效果,即可让整行 QItem 响应点击切换选中状态。示例(完整源码见 InaList.vue):

<q-list> <q-item tag="label" v-ripple> <q-item-section avatar> <q-radio v-model="color" val="teal" color="teal" /> </q-item-section> <q-item-section> <q-item-label>Teal</q-item-label> </q-item-section> </q-item> <q-item tag="label" v-ripple> <q-item-section avatar> <q-radio v-model="color" val="orange" color="orange" /> </q-item-section> <q-item-section> <q-item-label>Orange</q-item-label> <q-item-label caption>With description</q-item-label> </q-item-section> </q-item> </q-list>

其实现要点在于:QRadio 内部始终渲染一个隐藏的原生<input type="radio">(即使未指定name),源码注释明确说明"该原生 input 负责让包裹它的<label>将点击转发给组件"(QRadio.js),这正是<q-item tag="label">能够联动切换的底层原因。

十二、原生表单提交:name 属性与 formData

当 QRadio 位于带有actionmethod的原生表单中(例如与 ASP.NET 控制器对接),必须为 QRadio 指定name属性,否则 formData 中不会包含该字段。示例(完整源码见 NativeForm.vue):

<q-form @submit="onSubmit" class="q-gutter-md"> <q-radio name="shape" v-model="shape" val="line" label="Line" /> <q-radio name="shape" v-model="shape" val="rectangle" label="Rectangle" /> <q-radio name="shape" v-model="shape" val="ellipse" label="Ellipse" /> <q-radio name="shape" v-model="shape" val="polygon" label="Polygon" /> <div> <q-btn label="Submit" type="submit" color="primary" /> </div> </q-form>

提交后即可从new FormData(evt.target)中读取以name为键、val为值的字段。

源码中formAttrs函数负责生成原生 input 属性(QRadio.js):

const formAttrs = () => { const prop = { type: 'radio' } if (props.name !== void 0) { Object.assign(prop, { '.checked': isTrue.value, '^checked': isTrue.value ? 'checked' : void 0, name: props.name, value: props.val }) } return prop }

再经useFormInject注入到渲染树中。注意:原生表单提交时所有值都会被转换为字符串,因此这种情况下请不要使用 Object 作为val(文档原话,见 radio.md)。

十三、无障碍支持(v2.25+)

自 v2.25 起,QRadio 内置了完整的无障碍语义(详见 radio.md,以及源码中根节点属性的实现 QRadio.js):

无障碍特性实现方式
语义角色根节点暴露role="radio"
选中状态通过aria-checked="true/false"反映
可访问名称labelprop 同时作为aria-label(未提供时可用默认插槽内容)
禁用状态禁用时输出aria-disabled="true"
键盘可达可通过Tab聚焦(受tabindex属性控制)
键盘选中EnterSpace触发选中

键盘逻辑在源码中有完整对应:onKeydown拦截 Enter(13) 与 Space(32) 的默认行为,onKeyup中同一键位触发onClick([QRadio.js](https://link.gitcode.com/i/76bdfbd36024051dde6674bb7ed0591e#L41-L45, L141-L145))。tabindex计算为禁用时返回-1,否则取传入值或默认0(QRadio.js)。

[!IMPORTANT] 独立的 QRadio 并不感知其兄弟节点:每个 QRadio 都是独立的 Tab 停靠点,且不存在包裹它们的radiogroup语义。若需要完整的 WAI-ARIA radio group 模式(整个组只有一个 Tab 停靠点,方向键在组内移动焦点与选中项,即 roving tabindex),请将单选框包裹在 QOptionGroup 中,详见 option-group.md。

十四、组件方法:set

QRadio 暴露了一个公开方法set,作用是将该单选框的 v-model 设置为自身的val(见 QRadio.json 与源码 QRadio.js):

Object.assign(proxy, { set: onClick })

set就是组件内部的点击处理器本身:调用它等价于一次程序化点击,可在父组件中通过模板引用(ref)触发选中。

十五、默认插槽与 API 速查

label属性外,QRadio 的默认插槽也可作为标签内容(当未指定label时),源码中通过hMergeSlot(slots.default, [props.label])优先合并labelprop 与插槽内容(QRadio.js)。QRadio.json对插槽的说明为:"除非指定了 label prop,否则默认插槽可用作标签;建议使用字符串"(QRadio.json)。

属性速查表(来自 QRadio.json)

属性类型说明
model-valueAnyv-model 绑定值(必填)
valAny选中时写入 v-model 的实际值(必填)
labelString控件旁显示的文案
left-labelBoolean标签显示在左侧
checked-iconString选中态图标(替换默认设计)
unchecked-iconString未选中态图标(替换默认设计)
colorString选中态颜色(Quasar 调色板)
keep-colorBoolean未选中时也保留指定颜色
darkBoolean强制暗色模式
denseBoolean紧凑模式
disableBoolean禁用
tabindexString/Number焦点 Tab 顺序

事件与插槽

  • 事件update:model-value—— 需要更新模型时触发(v-model 依赖),参数为value(新模型值)与evt(原生事件);
  • 插槽default—— 标签内容(label优先)。

十六、进一步探索

  • 组件实现:阅读 QRadio.js 可了解渲染函数、表单注入与键盘事件全貌;
  • API 定义:见 QRadio.json;
  • 样式定义:见 QRadio.sass;
  • 组件测试:见 QRadio.test.js 与 QRadio.hydration.test.js,可验证点击、禁用、表单提交等行为;
  • 全部示例源码:见 QRadio 示例目录(Standard、WithIcons、Dense、Coloring、OnDarkBackground、Disable、LabelPosition、StandardSizes、OptionGroup、InaList、NativeForm 共 11 个用例);
  • 关联组件:QOptionGroup(文档)、QButtonToggle(文档)、QCheckbox(文档)、QToggle(文档)。
  • 前端
  • UI组件
  • 跨平台

【免费下载链接】quasar

Quasar Framework - Build high-performance VueJS user interfaces in record time

项目地址:https://gitcode.com/gh_mirrors/qu/quasar
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询