130 lines
3.4 KiB
TypeScript
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>
|
|
)
|
|
},
|
|
})
|