Files
workspace/code/base-project/base-vue/packages/ao-design/src/collapse/collapse-group.tsx
T
2025-09-22 17:30:00 +08:00

130 lines
3.4 KiB
TypeScript

import type { PropType, VNode } from 'vue'
import { defineComponent, provide, reactive, ref, watch } from 'vue'
import { getPrefixCls } from '../_utils/getPrefixCls'
import { collapseGroupKey } from './context'
export default defineComponent({
name: 'collapse',
props: {
activeKey: {
type: [String, Number, Boolean, Array] as PropType<
string | number | boolean | (string | number | boolean)[]
>,
default: undefined,
},
defaultActiveKey: {
type: [String, Number, Boolean, Array] as PropType<
string | number | boolean | (string | number | boolean)[]
>,
default: undefined,
},
borderLess: {
type: Boolean,
default: true,
},
defaultExpandAll: {
type: Boolean,
default: true,
},
disabled: {
type: Boolean,
default: false,
},
accordion: {
type: Boolean,
default: true,
},
expandIcon: {
type: [Boolean, String, Object, Function] as PropType<
boolean | string | VNode | ((args: { expanded: boolean }) => VNode)
>,
default: true,
},
expandIconPlacement: {
type: String as PropType<'left' | 'right'>,
default: 'left',
},
destroyOnHide: {
type: Boolean,
default: false,
},
class: {
type: [String, Array, Object],
default: '',
},
style: {
type: Object,
default: () => ({}),
},
},
emits: ['update:activeKey', 'change'],
setup(props, { slots, emit }) {
const prefixCls = getPrefixCls('collapse-group')
const _activeKey = ref(props.activeKey ?? props.defaultActiveKey ?? (!props.accordion ? [] : undefined))
watch(
() => props.activeKey,
(newVal) => {
_activeKey.value = newVal ?? (!props.accordion ? [] : undefined)
},
)
const handleChange = (val: string | number | boolean, e: Event) => {
// 外部 v-model 类型决定内部 value 的类型
const isArrayMode = Array.isArray(_activeKey.value)
if (isArrayMode) {
const arr = [...(_activeKey.value as (string | number | boolean)[])]
const idx = arr.indexOf(val)
if (idx >= 0) {
arr.splice(idx, 1)
}
else {
if (props.accordion)
arr.length = 0 // 单选时只保留最后一个
arr.push(val)
}
_activeKey.value = arr
emit('update:activeKey', arr)
emit('change', arr, e)
}
else {
// 非数组模式:单选或多选时非数组 v-model
const newVal = _activeKey.value === val ? undefined : val
_activeKey.value = newVal
emit('update:activeKey', newVal)
emit('change', newVal, e)
}
}
provide(
collapseGroupKey,
reactive({
name: 'AoCollapseGroup' as const,
activeKey: _activeKey,
disabled: props.disabled,
defaultExpandAll: props.defaultExpandAll,
expandIcon: props.expandIcon,
expandIconPlacement: props.expandIconPlacement,
destroyOnHide: props.destroyOnHide,
borderLess: props.borderLess,
slots,
handleChange,
}),
)
return () => (
<div
class={[
prefixCls,
props.class,
{ [`${prefixCls}-border-less`]: props.borderLess },
]}
style={{ ...props.style }}
>
{ slots.default?.()}
</div>
)
},
})