ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

radix-vue 中 SelectValue 组件完全指南:占位符、插槽与选中值渲染原理

radix-vue 中 SelectValue 组件完全指南:占位符、插槽与选中值渲染原理 radix-vue 中 SelectValue 组件完全指南占位符、插槽与选中值渲染原理【免费下载链接】radix-vueAn open-source UI component library for building high-quality, accessible design systems and web apps for Vue. Previously Radix Vue项目地址: https://gitcode.com/GitHub_Trending/ra/radix-vueSelectValue 是 radix-vue现 Reka UISelect 组件体系中负责回显选中内容的核心展示部件它内置于触发器内部根据当前选中值自动渲染对应选项的文本。本文围绕 docs/content/meta/SelectValue.md 的 API 定义结合 SelectValue.vue 的源码实现完整讲解其三个 Props、两个插槽、占位符机制、多选模式行为以及与之配套的源码级渲染原理帮助你在实际项目中正确使用并深度定制 Select 的取值展示。SelectValue 在 Select 组件体系中的位置SelectValue 是 Select 众多子部件之一通常与 SelectRoot、SelectTrigger、SelectContent、SelectItem 等组合使用。官方文档 Select 组件指南 对其定位描述为The part that reflects the selected value. By default the selected items text will be rendered即默认渲染当前选中项的文本同时提示不应为了确保正确定位而对其进行样式设置It should not be styled to ensure correct positioning。一个标准的最小组合结构如下SelectRoot SelectTrigger SelectValue / SelectIcon / /SelectTrigger SelectPortal SelectContent !-- SelectItem ... -- /SelectContent /SelectPortal /SelectRoot从源码导出清单看SelectValue 与 SelectRoot、SelectTrigger、SelectItem 等一并从 packages/core/src/Select/index.ts 中导出属于 Select 模块的一等公民export { default as SelectValue, type SelectValueProps, } from ./SelectValue.vueProps 详解根据 SelectValue.md 中的 PropsTableSelectValue 共接受三个属性全部为可选NameDescriptionTypeRequiredDefaultasThe element or component this component should render as. Can be overwritten by asChild.AsTag \| ComponentNospanasChildChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details.booleanNo-placeholderThe content that will be rendered inside the SelectValue when no value or defaultValue is set.stringNo对应的类型定义与默认值在源码中SelectValue.vue 与 同文件 L18-L21export interface SelectValueProps extends PrimitiveProps { /** The content that will be rendered inside the SelectValue when no value or defaultValue is set. */ placeholder?: string } const props withDefaults(definePropsSelectValueProps(), { as: span, placeholder: , })as控制渲染的元素标签as决定 SelectValue 最终渲染成什么元素默认值为span。这在语义上很合理——选中值展示是一个非交互的文本区域span 是中性且不影响布局的选择。由于该组件继承自PrimitiveProps它基于项目内的 Primitive 基础组件packages/core/src/Primitive实现因此as可以传入任意有效的 HTML 标签名AsTag或自定义 Vue 组件Component。asChild合并子元素的行为与属性asChild是 radix-vue 系列的通用组合机制当设为true时组件不再渲染自己的元素而是把自身的 props 与行为合并到传入的单个子元素上。对于 SelectValue一个典型场景是将选中的文本内容直接渲染进自定义的展示结构如 tooltip 触发器、自定义排版容器中同时保留data-placeholder等数据属性。placeholder无值时的占位文本placeholder是 SelectValue 最常用的业务属性默认空字符串。它的作用时机由源码严格界定——仅在当前没有选中任何值时渲染。判断逻辑位于 SelectValue.vueconst slotText computed(() { return selectedLabel.value.length ? selectedLabel.value.join(, ) : props.placeholder })也就是说一旦存在选中值占位符立即让位于真实的选中文本只有在selectedLabel为空数组无选中值时placeholder才会作为兜底内容显示。插槽Slots与作用域数据SelectValue 暴露两个作用域插槽让你可以完全接管渲染逻辑。根据 SelectValue.md 的 SlotsTableNameDescriptionTypeselectedLabelstring[]modelValueAcceptableValue \| AcceptableValue[] \| undefined插槽的注入实现位于 SelectValue.vueslot :selected-labelselectedLabel :model-valuerootContext.modelValue.value {{ slotText }} /slotselectedLabel解析后的选中文本数组selectedLabel的类型是string[]它由组件根据当前modelValue在选项集合中反查得到。核心计算逻辑SelectValue.vueconst selectedLabel computed(() { let list: string[] [] const options Array.from(rootContext.optionsSet.value) const getOption (value?: AcceptableValue) options.find(option valueComparator(value, option.value, rootContext.by)) if (Array.isArray(rootContext.modelValue.value)) { list rootContext.modelValue.value.map(value getOption(value)?.textContent ?? ) } else { list [getOption(rootContext.modelValue.value)?.textContent ?? ] } return list.filter(Boolean) })这里有几个值得注意的实现细节数据来源是rootContext.optionsSet所有已注册的选项SelectItem会把自己含value、disabled、textContent注册进 SelectRoot 维护的optionsSet参见 SelectRoot.vue 中optionsSet: RefSetSelectOption以及onOptionAdd/onOptionRemove。SelectValue 展示的文本本质上来自选项的textContent即SelectItemText渲染出的内容。反查匹配依赖by比较器匹配时调用valueComparator该函数支持按字段名、自定义函数或深度相等isEqual比较对象值具体实现在 packages/core/src/Select/utils.ts。多选模式返回多元素数组当modelValue是数组即 SelectRoot 设置了multiple时每个值都会映射为对应的文本当值是单一值时包装为单元素数组最后统一filter(Boolean)剔除反查失败产生的空串。modelValue原始的选中值modelValue插槽暴露的是未经反查的原始值类型为AcceptableValue | AcceptableValue[] | undefined。它直接取自 SelectRoot 的rootContext.modelValue.value。当你需要基于原始值而不是文本做定制渲染——比如显示图标、编号或格式化日期——可以使用这个插槽。占位符的完整运行机制何时显示占位符占位符的显示条件由两处共同决定SelectValue 自身的渲染逻辑selectedLabel为空数组时才输出placeholder见上文slotText。数据属性标记SelectValue 在模板中通过:data-placeholder将占位状态暴露给样式层SelectValue.vuePrimitive :refforwardRef :asas :as-childasChild :style{ pointerEvents: none } :data-placeholderselectedLabel.length ? undefined : props.placeholder data-placeholder属性仅在处于占位状态时存在其值即占位文本你可以据此写出选中态与占位态样式切换的 CSS例如官方 demodocs/components/demo/Select/tailwind/index.vue中触发器的样式data-[placeholder]:text-green9即当触发器内 SelectValue 处于占位态时将文本颜色切换为较浅的绿色给用户明确的尚未选择视觉反馈。无选中值的判定源头SelectValue 只是消费者真正的空值判定在 SelectRoot 侧。isEmptyModelValue的计算逻辑SelectRoot.vueconst isEmptyModelValue computed(() { if (multiple.value Array.isArray(modelValue.value)) return modelValue.value?.length 0 else return isNullish(modelValue.value) })多选模式下空数组视为无值单选模式下null/undefined视为无值。此外工具函数shouldShowPlaceholderutils.ts还会把空字符串也归入空值范畴。这套判定同时被 SelectTrigger 使用保证触发器与取值展示在占位语义上保持一致。多选multiple模式下的展示行为当 SelectRoot 开启multiple后modelValue变为数组SelectValue 的展示也随之变化selectedLabel返回数组每个选中值对应的选项文本构成一个字符串数组。默认输出以逗号连接slotText使用join(, )将多个文本拼接例如Apple, Banana。这一行为在 SelectValue.vue 中直接可见。官方多选演示packages/core/src/Select/story/SelectDemo.story.vue展示了 SelectValue 配合多选与自定义占位符的典型写法SelectRoot v-modelfruit multiple SelectTrigger aria-labelCustomise options SelectValue placeholderPlease select a fruit / Icon iconradix-icons:chevron-down / /SelectTrigger !-- ... -- /SelectRoot如果你需要更精细的多选展示例如用 tag/chip 形式分别渲染每个选项应当使用selectedLabel与modelValue插槽自行实现而非依赖默认的逗号拼接。交互细节与可访问性要点SelectValue 虽然主要负责展示但它还承担着与无障碍和表单相关的隐含职责pointerEvents 禁用模板中强制设置style{ pointerEvents: none }SelectValue.vue保证点击/拖拽命中不会落在值文本上而是穿透到 SelectTrigger 的按钮区域——这正是官方不应单独样式化建议的原因之一。辅助隐藏原生表单控件在受控表单SelectRoot 设置了name且处于表单上下文中场景下SelectRoot 会渲染一个aria-hidden的BubbleSelect原生selectSelectRoot.vue而 SelectValue 通过onMounted把自己的 DOM 元素注册到rootContext.valueElementSelectValue.vue参与组件内部对取值展示元素的管理。data-placeholder语义该数据属性不仅是样式钩子也可被自动化测试与辅助技术识别为当前处于占位状态。卸载清理测试packages/core/src/Select/test/SelectUnmountCleanup.vue中的用例也验证了SelectValue placeholder与 SelectRoot 组合在组件卸载、关闭流程中的稳定性。实战完整可运行示例结合官方 demo 与上文原理下面是一个基于 Tailwind 的完整单文件示例参考 docs/components/demo/Select/tailwind/index.vue覆盖占位符、选中态回显与分组选项script setup langts import { Icon } from iconify/vue import { ref } from vue import { SelectContent, SelectGroup, SelectItem, SelectItemIndicator, SelectItemText, SelectLabel, SelectPortal, SelectRoot, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, SelectViewport, } from reka-ui const fruit ref() const options [Apple, Banana, Blueberry, Grapes, Pineapple] const vegetables [Aubergine, Broccoli, Carrot, Courgette, Leek] /script template SelectRoot v-modelfruit SelectTrigger classinline-flex min-w-[160px] items-center justify-between rounded-lg px-[15px] text-xs h-[35px] gap-[5px] bg-white border shadow-sm focus:shadow-[0_0_0_2px] focus:shadow-black contenteditable="false">【免费下载链接】radix-vueAn open-source UI component library for building high-quality, accessible design systems and web apps for Vue. Previously Radix Vue项目地址: https://gitcode.com/GitHub_Trending/ra/radix-vue创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表