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>, default: () => [], }, defaultValue: { type: Array as PropType>, 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>, default: [], }, spaceProps: { type: Object as PropType>, 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 (
handleChange(opt[props.valueField], e)} > {slots.radio({ data: opt, checked: _value.value === opt[props.valueField] })}
) } return ( {labelContent} ) }) } const spaceSize = ['default', 'card', 'pureCard'].includes(groupType.value) ? [6, 6] : props.spaceProps.size ?? 0 return () => ( {props.options.length > 0 ? renderOptions() : slots.default?.()} ) }, })