Skip to content

Commit

Permalink
fix(Collapse): 手风琴模式下,modelValue 数据处理异常 (#522)
Browse files Browse the repository at this point in the history
- 调整 Collapse 文档调用 demo 组件语法
- 将 UseNormalModelReturn 移入 useModel 文件中
  • Loading branch information
1zumii committed Dec 1, 2023
1 parent dd36fe7 commit 194428b
Show file tree
Hide file tree
Showing 12 changed files with 115 additions and 78 deletions.
6 changes: 6 additions & 0 deletions components/_util/use/useModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ type UseNormalModelOptions = {
defaultValue?: any;
};

// TODO: 后续考虑如何并入 useNormalModel
export type UseNormalModelReturn<
Props extends Record<string, unknown>,
Key extends keyof Props,
> = [WritableComputedRef<Props[Key]>, (value: Props[Key]) => void];

export const useNormalModel = (
props: Record<string, any>,
emit: any,
Expand Down
3 changes: 1 addition & 2 deletions components/calendar/useCalendarData.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { computed, ref } from 'vue';
import { Day } from 'date-fns';
import { isNil } from 'lodash-es';
import { useNormalModel } from '../_util/use/useModel';
import { UseNormalModelReturn, useNormalModel } from '../_util/use/useModel';
import { CalendarEvent, CalendarInnerProps, CalendarShortcut } from './props';
import {
UseNormalModelReturn,
convertCalendarDateToUnixTime,
convertUnixTimeToCalendarDate,
generateCalendarDates,
Expand Down
7 changes: 0 additions & 7 deletions components/calendar/utils.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
import { Day, addMonths, getDaysInMonth, set, subDays } from 'date-fns';
import { isNil } from 'lodash-es';
import { WritableComputedRef } from 'vue';
import { prefixCls } from './const';
import { CalendarDate, UnixTime } from './types';

export const cls = (className: string) => `${prefixCls}-${className}`;

// TODO: 后续考虑如何并入 useNormalModel
export type UseNormalModelReturn<
Props extends Record<string, unknown>,
Key extends keyof Props,
> = [WritableComputedRef<Props[Key]>, (value: Props[Key]) => void];

/**
* 根据一个 Date,计算其所在月份日历
*
Expand Down
68 changes: 57 additions & 11 deletions components/collapse/collapse.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,37 +5,83 @@
</template>

<script lang="ts">
import { provide, defineComponent, computed } from 'vue';
import { provide, defineComponent, computed, watch } from 'vue';
import { isNil } from 'lodash-es';
import { useTheme } from '../_theme/useTheme';
import { useNormalModel } from '../_util/use/useModel';
import { UseNormalModelReturn, useNormalModel } from '../_util/use/useModel';
import { collapseEmits, collapseProps } from './collapseExpose';
import { useNamespace } from './useNamespace';
import { arrowPositionKey, collapseContextKey } from './common';
import { COMPONENT_NAME, arrowPositionKey, collapseContextKey } from './common';
import type { CollapseActiveName } from './common';
export default defineComponent({
name: 'FCollapse',
name: COMPONENT_NAME,
props: collapseProps,
emits: collapseEmits,
setup(props, { emit }) {
useTheme();
const [activeNames, setActiveNames] = useNormalModel(props, emit);
const [modelValue, setModelValue]: UseNormalModelReturn<
typeof props,
'modelValue'
> = useNormalModel(props, emit);
const activeNames = computed<(string | number)[]>({
get: () => {
if (isNil(modelValue.value)) return [];
if (props.accordion) {
if (Array.isArray(modelValue.value)) {
console.warn(
`${COMPONENT_NAME}: 手风琴模式下 modelValue 不支持数组`,
);
return [];
}
return [modelValue.value];
} else {
if (!Array.isArray(modelValue.value)) {
console.warn(
`${COMPONENT_NAME}: 非手风琴模式下 modelValue 仅支持数组`,
);
return [];
}
return modelValue.value;
}
},
set: (names) => {
if (props.accordion) {
setModelValue(names[0]);
} else {
setModelValue(names);
}
},
});
// 手风琴模式变化时,重置 modelValue
watch(
() => props.accordion,
() => {
activeNames.value = [];
},
);
const handleItemClick = (name: CollapseActiveName) => {
let _activeNames = [...activeNames.value];
const index = _activeNames.indexOf(name);
if (props.accordion) {
setActiveNames([activeNames.value[0] === name ? '' : name]);
_activeNames = index > -1 ? [] : [name];
} else {
const _activeNames = [...activeNames.value];
const index = _activeNames.indexOf(name);
if (index > -1) {
_activeNames.splice(index, 1);
} else {
_activeNames.push(name);
}
setActiveNames(_activeNames);
}
activeNames.value = _activeNames;
};
provide(collapseContextKey, {
Expand All @@ -51,10 +97,10 @@ export default defineComponent({
arrow: props?.arrow,
embedded: computed(() => props?.embedded),
});
return {
rootKls,
activeNames,
setActiveNames,
};
},
});
Expand Down
4 changes: 0 additions & 4 deletions components/collapse/collapseExpose.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@ type Arrayable<T> = T | T[];
export type CollapseModelValue = Arrayable<CollapseActiveName>;
export type Mutable<T> = { -readonly [P in keyof T]: T[P] }; // 移除只读特性

const mutable = <T extends readonly any[] | Record<string, unknown>>(val: T) =>
val as Mutable<typeof val>;

export const emitChangeFn = (value: CollapseModelValue) =>
typeof isNumber(value) || isString(value) || Array.isArray(value);

Expand All @@ -23,7 +20,6 @@ export const collapseProps = {
},
modelValue: {
type: definePropType<CollapseModelValue>([Array, String, Number]),
default: () => mutable([] as const), // 常量
},
embedded: {
type: Boolean,
Expand Down
2 changes: 2 additions & 0 deletions components/collapse/common.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type { InjectionKey, PropType, Ref } from 'vue';

export const COMPONENT_NAME = 'FCollapse';

export const definePropType = <T>(val: any): PropType<T> => val;

export const generateId = (): number => Math.floor(Math.random() * 10000);
Expand Down
33 changes: 20 additions & 13 deletions docs/.vitepress/components/collapse/accordion.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
<template>
<div class="demo-collapse">
<FCollapse v-model="activeName" accordion :embedded="false">
<FSpace vertical>
<FSwitch v-model="accordion">手风琴模式</FSwitch>
<FCollapse
v-model="activeName"
:accordion="accordion"
:embedded="false"
>
<FCollapseItem title="Consistency" name="1">
<div>
岁月静好,浅笑安然。打开记忆的闸门,仿佛又回到了那年那月那时光,仿佛又见到你送给我的那盆清香茉莉,在细雨潇潇的夜晚,所呈现出来的洁净和楚楚动人。以前的过往总是在记忆深处,以固有的姿态,以从未稍离的执着提醒我,生命中有一种存在,叫以前。
Expand All @@ -22,17 +27,19 @@
</div>
</FCollapseItem>
</FCollapse>
</div>
</FSpace>
</template>

<script>
import { ref } from 'vue';
export default {
setup() {
const activeName = ref('1');
return {
activeName,
};
},
};
<script setup>
import { ref, watch } from 'vue';
const accordion = ref(true);
const activeName = ref('1');
watch(activeName, (name) =>
console.log(
'[FCollapse.accordion] activeName',
JSON.parse(JSON.stringify(name)),
),
);
</script>
7 changes: 2 additions & 5 deletions docs/.vitepress/components/collapse/arrowleft.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div class="demo-collapse">
<FCollapse v-model="activeNames" :arrow="'left'" @change="handleChange">
<FCollapse v-model="activeNames" :arrow="'left'">
<FCollapseItem title="Consistency" name="1">
<div>
岁月静好,浅笑安然。打开记忆的闸门,仿佛又回到了那年那月那时光,仿佛又见到你送给我的那盆清香茉莉,在细雨潇潇的夜晚,所呈现出来的洁净和楚楚动人。以前的过往总是在记忆深处,以固有的姿态,以从未稍离的执着提醒我,生命中有一种存在,叫以前。
Expand Down Expand Up @@ -31,12 +31,9 @@ import { ref } from 'vue';
export default {
setup() {
const activeNames = ref(['1']);
const handleChange = (value) => {
console.log('[collapse.arrowleft] [handleChange] value:', value);
};
return {
activeNames,
handleChange,
};
},
};
Expand Down
7 changes: 2 additions & 5 deletions docs/.vitepress/components/collapse/basic.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div class="demo-collapse">
<FCollapse v-model="activeNames" @change="handleChange">
<FCollapse v-model="activeNames">
<FCollapseItem title="Consistency" name="1">
<div>
岁月静好,浅笑安然。打开记忆的闸门,仿佛又回到了那年那月那时光,仿佛又见到你送给我的那盆清香茉莉,在细雨潇潇的夜晚,所呈现出来的洁净和楚楚动人。以前的过往总是在记忆深处,以固有的姿态,以从未稍离的执着提醒我,生命中有一种存在,叫以前。
Expand Down Expand Up @@ -31,12 +31,9 @@ import { ref } from 'vue';
export default {
setup() {
const activeNames = ref(['1']);
const handleChange = (value) => {
console.log('[collapse.basic] [handleChange] value:', value);
};
return {
activeNames,
handleChange,
};
},
};
Expand Down
10 changes: 1 addition & 9 deletions docs/.vitepress/components/collapse/embedded.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
<template>
<div class="demo-collapse">
<FSwitch v-model="embedded"></FSwitch>
<FCollapse
v-model="activeNames"
:embedded="embedded"
@change="handleChange"
>
<FCollapse v-model="activeNames" :embedded="embedded">
<FCollapseItem title="Consistency" name="1">
<div>
岁月静好,浅笑安然。打开记忆的闸门,仿佛又回到了那年那月那时光,仿佛又见到你送给我的那盆清香茉莉,在细雨潇潇的夜晚,所呈现出来的洁净和楚楚动人。以前的过往总是在记忆深处,以固有的姿态,以从未稍离的执着提醒我,生命中有一种存在,叫以前。
Expand Down Expand Up @@ -36,14 +32,10 @@ import { ref } from 'vue';
export default {
setup() {
const activeNames = ref(['1']);
const handleChange = (value) => {
console.log('[collapse.embedded] [handleChange] value:', value);
};
const embedded = ref(false);
return {
embedded,
activeNames,
handleChange,
};
},
};
Expand Down
44 changes: 23 additions & 21 deletions docs/.vitepress/components/collapse/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,50 +14,52 @@ app.use(FCollapse);

可同时展开多个面板,面板之间不影响

--BASIC
:::demo
basic.vue
:::

## 手风琴效果

每次只能展开一个面板

通过 `accordion` 属性来设置是否以手风琴模式显示。

--ACCORDION
:::demo
accordion.vue
:::

## 箭头在左边

箭头在左边配置

--ARROWLEFT
:::demo
arrowleft.vue
:::

## 背景色

embedded 控制背景色

--EMBEDDED
:::demo
embedded.vue
:::

## 自定义面板标题

除了可以通过 `title` 属性以外,还可以通过具名 `slot` 来实现自定义面板的标题内容,以实现增加图标等效果。

--CUSTOMIZATION

--CODE
:::demo
customization.vue
:::

## Collapse 属性

| 属性名 | 详情 | 类型 | 可选值 | 默认值 |
| --------------------- | ----------------------------------------------------------------------- | ---------------------------------------------------- | ------ | ------ |
| model-value / v-model | 当前激活的面板(如果是手风琴模式,绑定值类型需要为 string,否则为 array) | string (accordion mode) / array (non-accordion mode) |||
| accordion | 是否手风琴模式 | boolean || false |
| arrow | 箭头位置 ( left, right ) ,默认右边 | string || right |
| embedded | 内容使用更深的背景色展现嵌入效果 | boolean || true |

## Collapse 事件

| 属性名 | 说明 | 回调参数 |
| ------ | -------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
| change | 当前激活面板改变时触发(如果是手风琴模式,参数 activeNames 类型为 string,否则为 array) | (activeNames: array (non-accordion mode) / string (accordion mode)) |
| model-value / v-model | 当前激活的面板(如果是手风琴模式,绑定值类型需要为 string,否则为 array) | string (accordion mode) / array (non-accordion mode) | - | - |
| accordion | 是否手风琴模式 | boolean | - | false |
| arrow | 箭头位置 ( left, right ) ,默认右边 | string | - | right |
| embedded | 内容使用更深的背景色展现嵌入效果 | boolean | - | true |

## Collapse 插槽

Expand All @@ -69,13 +71,13 @@ embedded 控制背景色

| 属性名 | 说明 | 类型 | 可选值 | 默认值 |
| -------- | ---------- | ------------- | ------ | ------ |
| name | 唯一标志符 | string/number | | |
| title | 面板标题 | string | | |
| disabled | 是否禁用 | boolean | | |
| name | 唯一标志符 | string/number | - | - |
| title | 面板标题 | string | - | - |
| disabled | 是否禁用 | boolean | - | - |

## Collapse Item 插槽

| 属性名 | 说明 |
| ------ | ---------------- |
| | 折叠项的内容 |
| - | 折叠项的内容 |
| title | 折叠项标题的内容 |
2 changes: 1 addition & 1 deletion docs/.vitepress/configs/sidebar/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export default {
link: '/zh/components/layout',
},
{
text: 'Grid 删格',
text: 'Grid 栅格',
link: '/zh/components/grid',
},
{
Expand Down

0 comments on commit 194428b

Please sign in to comment.