Files
workspace/code/base-project/base-vue/packages/ao-design/src/checkbox/checkbox-group.tsx
T
2025-09-17 14:49:15 +08:00

177 lines
4.5 KiB
TypeScript

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 Checkbox from './checkbox'
import { checkboxGroupKey } from './context'
interface CheckboxOption {
label?: string | RenderFunction
value?: string | number
extra?: string | RenderFunction
disabled?: boolean
[key: string]: any
}
export default defineComponent({
name: 'CheckboxGroup',
props: {
modelValue: {
type: Array as PropType<Array<string | number | boolean>>,
default: () => [],
},
defaultValue: {
type: Array as PropType<Array<string | number | boolean>>,
default: () => [],
},
disabled: {
type: Boolean,
default: false,
},
labelField: {
type: String,
default: 'label',
},
valueField: {
type: String,
default: 'value',
},
extraField: {
type: String,
default: 'extra',
},
options: {
type: Array as PropType<Array<string | number | CheckboxOption>>,
default: [],
},
spaceProps: {
type: Object as PropType<Record<string, any>>,
default: () => ({}),
},
type: {
type: String as PropType<'default' | 'card' | 'pureCard'>,
default: 'default',
},
class: {
type: [String, Array, Object],
default: '',
},
style: {
type: Object,
default: () => ({}),
},
},
emits: ['update:modelValue', 'change'],
setup(props, { slots, emit }) {
const prefixCls = getPrefixCls('checkbox-group')
const _value = ref(props.modelValue ?? props.defaultValue ?? [])
watch(() => props.modelValue, (newVal) => {
_value.value = newVal ?? []
})
const groupDisabled = computed(() => props.disabled)
const groupType = computed(() => props.type)
const handleChange = (val: string | number | boolean, e: Event) => {
const current = _value.value ? [..._value.value] : []
const index = current.indexOf(val)
if (index > -1) {
// 已存在 -> 取消选中
current.splice(index, 1)
}
else {
// 不存在 -> 添加
current.push(val)
}
// 非受控模式才更新内部值
if (props.modelValue === undefined) {
_value.value = current
}
// 通知外部
emit('update:modelValue', current)
emit('change', current, e)
}
// 提供 context 给 Radio 使用
provide(checkboxGroupKey, reactive({
name: 'AoCheckboxGroup' as const,
value: _value,
disabled: groupDisabled,
type: groupType,
slots,
handleChange,
}))
const renderOptions = () => {
return props.options.map((option) => {
const opt
= 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]
const extraContent = slots.extra
? slots.extra({ data: opt })
: typeof opt[props.extraField] === 'function'
? opt[props.extraField]()
: opt[props.extraField]
const isChecked
= _value.value.includes(opt[props.valueField])
if (slots.radio) {
return (
<div
key={opt[props.valueField]}
onClick={e => handleChange(opt[props.valueField], e)}
>
{slots.radio({ data: opt, checked: _value.value === opt[props.valueField] })}
</div>
)
}
return (
<Checkbox
key={opt[props.valueField]}
value={opt[props.valueField]}
extra={extraContent}
disabled={opt.disabled ?? props.disabled}
checked={isChecked}
type={props.type}
>
{labelContent}
</Checkbox>
)
})
}
const spaceSize
= ['default', 'card', 'pureCard'].includes(groupType.value)
? [6, 6]
: props.spaceProps.size ?? 0
return () => (
<Space
align="start"
size={spaceSize}
{...props.spaceProps}
class={[
`${prefixCls}-${groupType.value}`,
]}
>
{props.options.length > 0 ? renderOptions() : slots.default?.()}
</Space>
)
},
})