u
This commit is contained in:
1 parent
104e0a78c6
commit
4d0d2f875e
13 files changed
+802
-226
No files matched your search
@@ -0,0 +1,176 @@
|
||||
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>
|
||||
)
|
||||
},
|
||||
})
|
||||
Reference in new issue
Block a user