This commit is contained in:
oneao committed 2025-09-15 17:31:18 +08:00
1 parent ae0ad2bd63
commit 5a7e96db02
12 files changed
+466 -85

No files matched your search

@@ -0,0 +1,112 @@
import type { PropType, RenderFunction } from 'vue'
import { computed, defineComponent, provide, reactive, ref, watch } from 'vue'
import { getPrefixCls } from '../_utils/getPrefixCls'
import Space from '../space/index'
import { radioGroupKey } from './context'
import Radio from './radio'
interface RadioOption {
label?: string | RenderFunction
value?: string | number
extra?: string | RenderFunction
disabled?: boolean
[key: string]: any
}
export default defineComponent({
name: 'RadioGroup',
props: {
modelValue: {
type: [String, Number, Boolean] as PropType<string | number | boolean>,
default: undefined,
},
defaultValue: {
type: [String, Number, Boolean] as PropType<string | number | boolean>,
default: '',
},
disabled: {
type: Boolean,
default: false,
},
labelField: {
type: String,
default: 'label',
},
valueField: {
type: String,
default: 'value',
},
options: {
type: Array as PropType<Array<string | number | RadioOption>>,
default: [],
},
spaceProps: {
type: Object as PropType<Record<string, any>>,
default: () => ({}),
},
},
emits: ['update:modelValue', 'change'],
setup(props, { emit, slots }) {
const prefixCls = getPrefixCls('radio-group')
// 内部值,优先使用 v-model
const _value = ref(props.modelValue ?? props.defaultValue)
watch(() => props.modelValue, (newVal) => {
if (newVal !== undefined) {
_value.value = newVal
}
})
const handleChange = (val: string | number | boolean, e: Event) => {
_value.value = val
emit('update:modelValue', val)
emit('change', val, e)
}
const groupDisabled = computed(() => props.disabled)
// 提供 context 给 Radio 使用
provide(radioGroupKey, reactive({
name: 'AoRadioGroup' as const,
value: _value,
disabled: groupDisabled,
slots,
handleChange,
}))
const renderOptions = () => {
return props.options.map((option) => {
// 标准化 option
const opt: RadioOption
= typeof option === 'string' || typeof option === 'number'
? { [props.labelField]: String(option), [props.valueField]: option }
: option
const labelContent = slots.label
? slots.label({ data: opt })
: typeof opt[props.labelField] === 'function'
? opt[props.labelField]()
: opt[props.labelField]
return (
<Radio
key={opt[props.valueField]}
value={opt[props.valueField]}
disabled={opt.disabled ?? props.disabled}
modelValue={_value.value === opt[props.valueField]}
>
{labelContent}
</Radio>
)
})
}
return () => (
<div class={[prefixCls]}>
<Space {...props.spaceProps}>
{props.options.length > 0 ? renderOptions() : slots.default?.()}
</Space>
</div>
)
},
})