Skip to content

Commit

Permalink
fix: 🐛 修复 Collapse 使用 toggleAall 方法时不会触发 before-expand 钩子的问题
Browse files Browse the repository at this point in the history
  • Loading branch information
Moonofweisheng committed Nov 22, 2024
1 parent 4bf8d1e commit b5e7e65
Show file tree
Hide file tree
Showing 8 changed files with 164 additions and 76 deletions.
90 changes: 70 additions & 20 deletions docs/component/collapse.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,20 +54,13 @@ const value = ref<string[]>(['item1'])

```html
<wd-collapse v-model="value">
<wd-collapse-item
v-for="(item, index) in itemList"
:before-expend="beforeExpend"
:key="index"
:title="item.title"
:name="item.name"
>
<wd-collapse-item v-for="(item, index) in itemList" :before-expend="beforeExpend" :key="index" :title="item.title" :name="item.name">
{{ item.body }}
</wd-collapse-item>
</wd-collapse>
```

```ts

import { useToast } from '@/uni_modules/wot-design-uni'
const toast = useToast()
const value = ref<string[]>(['item1'])
Expand Down Expand Up @@ -152,14 +145,37 @@ Collapse 查看更多的模式下,可以使用插槽定义自己想要的折
</wd-collapse>
```

## 嵌套使用

`collapse`可以嵌套使用,同时由于`collapse-item`的内容容器存在默认的`padding`,所以嵌套的`collapse`需要设置`custom-body-style`或者`custom-body-class`来覆盖默认样式。

:::tip 注意
`custom-body-style``custom-body-class``$LOWEST_VERSION$`及以上版本支持。
:::

```html
<wd-collapse v-model="collapseRoot">
<wd-collapse-item custom-body-style="padding:0 0 0 14px" v-for="item in 5" :key="item" :title="`标签${item}`" :name="`${item}`">
<wd-collapse v-model="collapseList[item - 1]">
<wd-collapse-item v-for="(item, index) in itemList" :key="index" :title="item.title" :name="item.name">{{ item.body }}</wd-collapse-item>
</wd-collapse>
</wd-collapse-item>
</wd-collapse>
```

```ts
const collapseRoot = ref<string[]>(['0'])
const collapseList = ref<Array<string[]>>([['item1'], ['item2'], ['item3'], ['item4'], ['item5']])
```

## CollapseItem Attributes

| 参数 | 说明 | 类型 | 可选值 | 默认值 | 最低版本 |
| ------------- | ----------------------------------------------------------- | -------- | ------ | ------ | -------- |
| name | 折叠栏的标识符 | string | - | - | - |
| title | 折叠栏的标题, 支持同名 slot 自定义内容 | string | - | '' | - |
| title | 折叠栏的标题, 支持同名 slot 自定义内容 | string | - | '' | - |
| disabled | 禁用折叠栏 | boolean | - | false | - |
| before-expend | 打开前的回调函数,返回 false 可以阻止打开,支持返回 Promise | Function | - | false | - |
| before-expend | 打开前的回调函数,返回 false 可以阻止打开,支持返回 Promise | Function | - | - | - |

### `before-expend` 执行时会传递以下回调参数:

Expand All @@ -185,22 +201,56 @@ Collapse 查看更多的模式下,可以使用插槽定义自己想要的折

## Methods

| 方法名 | 说明 | 参数 | 最低版本 |
| --- | --- | --- | --- |
| toggleAll | 切换所有面板展开状态,传 `true` 为全部展开,`false` 为全部收起,不传参为全部切换 | _options?: boolean \| object_ | 0.2.6 |
| 方法名 | 说明 | 参数 | 最低版本 |
| --------- | -------------------------------------------------------------------------------- | ------------------------------------ | -------- |
| toggleAll | 切换所有面板展开状态,传 `true` 为全部展开,`false` 为全部收起,不传参为全部切换 | `options?: CollapseToggleAllOptions` | 0.2.6 |

### toggleAll 方法示例

```html
<wd-collapse ref="collapse">
...
</wd-collapse>
```

```ts
import { ref } from 'vue'
import type { CollapseInstance } from '@/uni_modules/wot-design-uni/components/wd-collapse/types'

const collapseRef = ref<CollapseInstance>()

// 全部切换
collapseRef.value?.toggleAll()
// 全部展开
collapseRef.value?.toggleAll(true)
// 全部收起
collapseRef.value?.toggleAll(false)

// 全部全部切换,并跳过禁用项
collapseRef.value?.toggleAll({
skipDisabled: true
})
// 全部选中,并跳过禁用项
collapseRef.value?.toggleAll({
expanded: true,
skipDisabled: true
})
```

## Collapse Slot

| name | 说明 | 最低版本 |
| ---- | ---------------------------------------------------- | -------- |
| title |标题,便于开发者自定义标题(非 viewmore 使用) | 1.2.27 |
| more | 查看更多,便于开发者自定义查看更多类型的展开收起样式 | - |
| name | 说明 | 最低版本 |
| ----- | ---------------------------------------------------- | -------- |
| title | 标题,便于开发者自定义标题(非 viewmore 使用) | 1.2.27 |
| more | 查看更多,便于开发者自定义查看更多类型的展开收起样式 | - |

## CollapseItem 外部样式类

| 类名 | 说明 | 最低版本 |
| ------------ | ----------------------- | -------- |
| custom-class | collapseItem 根节点样式 | - |
| 类名 | 说明 | 最低版本 |
| ----------------- | ------------------------------ | ---------------- |
| custom-class | collapseItem 根节点样式 | - |
| custom-body-style | 自定义折叠面板内容容器的样式 | $LOWEST_VERSION$ |
| custom-body-class | 自定义折叠面板内容容器的样式类 | $LOWEST_VERSION$ |

**注意:组件内插槽样式不生效,因此使用插槽时需注意添加外部样式类**

Expand Down
2 changes: 1 addition & 1 deletion src/pages/collapse/Index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@

<demo-block title="嵌套" transparent>
<wd-collapse v-model="collapseRoot" @change="handleChange1">
<wd-collapse-item v-for="item in 5" :key="item" :title="`标签${item}`" :name="`${item}`">
<wd-collapse-item custom-body-style="padding:0 0 0 14px" v-for="item in 5" :key="item" :title="`标签${item}`" :name="`${item}`">
<wd-collapse v-model="collapseList[item - 1]">
<wd-collapse-item v-for="(item, index) in itemList" :key="index" :title="item.title" :name="item.name">
{{ item.body }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ $-checkbox-button-disabled-border: var(--wot-checkbox-button-disabled-border, rg

/* collapse */
$-collapse-side-padding: var(--wot-collapse-side-padding, $-size-side-padding) !default; // 左右间距
$-collapse-body-padding: var(--wot-collapse-body-padding, 14px 25px) !default; // body padding
$-collapse-body-padding: var(--wot-collapse-body-padding, 14px $-size-side-padding) !default; // body padding
$-collapse-header-padding: var(--wot-collapse-header-padding, 13px $-size-side-padding) !default; // 头部padding
$-collapse-title-color: var(--wot-collapse-title-color, rgba(0, 0, 0, 0.85)) !default; // 标题颜色
$-collapse-title-fs: var(--wot-collapse-title-fs, 16px) !default; // 标题字号
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@
padding: $-collapse-header-padding;
overflow: hidden;
user-select: none;

@include when(expanded) {
@include halfPixelBorder('bottom');
}

}

@include e(title) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
import type { ComponentPublicInstance, ExtractPropTypes, PropType } from 'vue'
import { baseProps, makeBooleanProp, makeRequiredProp, makeStringProp } from '../common/props'

export type CollapseItemBeforeExpand = (name: string) => void
export type CollapseItemBeforeExpand = (name: string) => boolean | Promise<unknown>

export const collapseItemProps = {
...baseProps,
/**
* 自定义折叠栏内容容器样式类名
*/
customBodyClass: makeStringProp(''),
/**
* 自定义折叠栏内容容器样式
*/
customBodyStyle: makeStringProp(''),
/**
* 折叠栏的标题, 可通过 slot 传递自定义内容
*/
Expand Down Expand Up @@ -33,7 +41,6 @@ export type CollapseItemExpose = {
getExpanded: () => boolean
/**
* 更新展开状态
* @returns Promise<void>
*/
updateExpand: () => Promise<void>
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
<template>
<view :class="`wd-collapse-item ${disabled ? 'is-disabled' : ''} is-border ${customClass}`" :style="customStyle">
<view :class="`wd-collapse-item__header ${isFirst ? 'wd-collapse-item__header-first' : ''}`" @click="handleClick">
<view
:class="`wd-collapse-item__header ${expanded ? 'is-expanded' : ''} ${isFirst ? 'wd-collapse-item__header-first' : ''}`"
@click="handleClick"
>
<slot name="title" :expanded="expanded" :disabled="disabled" :isFirst="isFirst">
<text class="wd-collapse-item__title">{{ title }}</text>
<wd-icon name="arrow-down" :custom-class="`wd-collapse-item__arrow ${expanded ? 'is-retract' : ''}`" />
</slot>
</view>
<view class="wd-collapse-item__wrapper" :style="contentStyle" @transitionend="handleTransitionEnd">
<view class="wd-collapse-item__body" :id="collapseId">
<view class="wd-collapse-item__body" :class="customBodyClass" :style="customBodyStyle" :id="collapseId">
<slot />
</view>
</view>
Expand All @@ -26,8 +29,8 @@ export default {

<script lang="ts" setup>
import wdIcon from '../wd-icon/wd-icon.vue'
import { computed, getCurrentInstance, onMounted, ref, watch, type CSSProperties } from 'vue'
import { addUnit, getRect, isArray, isDef, isPromise, objToStyle, requestAnimationFrame, uuid } from '../common/util'
import { computed, getCurrentInstance, onMounted, ref, type CSSProperties } from 'vue'
import { addUnit, getRect, isArray, isDef, isPromise, isString, objToStyle, requestAnimationFrame, uuid } from '../common/util'
import { useParent } from '../composables/useParent'
import { COLLAPSE_KEY } from '../wd-collapse/types'
import { collapseItemProps, type CollapseItemExpose } from './types'
Expand Down Expand Up @@ -66,33 +69,37 @@ const contentStyle = computed(() => {
return objToStyle(style)
})
const selected = computed(() => {
if (collapse) {
return collapse.props.modelValue
} else {
return []
}
/**
* 是否选中
*/
const isSelected = computed(() => {
const modelValue = collapse ? collapse?.props.modelValue || [] : []
const { name } = props
return (isString(modelValue) && modelValue === name) || (isArray(modelValue) && modelValue.indexOf(name as string) >= 0)
})
onMounted(() => {
updateExpand()
updateExpand(isSelected.value)
})
function updateExpand() {
return getRect(`#${collapseId.value}`, false, proxy).then((rect) => {
async function updateExpand(useBeforeExpand: boolean = true) {
try {
if (useBeforeExpand) {
await handleBeforeExpand()
}
initRect()
} catch (error) {
/* empty */
}
}
function initRect() {
getRect(`#${collapseId.value}`, false, proxy).then((rect) => {
const { height: rectHeight } = rect
height.value = isDef(rectHeight) ? Number(rectHeight) : ''
const name = props.name
requestAnimationFrame(() => {
if (isDef(selected.value)) {
if (
(typeof selected.value === 'string' && selected.value === name) ||
(isArray(selected.value) && selected.value.indexOf(name as string) >= 0)
) {
expanded.value = true
} else {
expanded.value = false
}
if (isSelected.value) {
expanded.value = true
} else {
expanded.value = false
}
Expand All @@ -110,40 +117,50 @@ function handleTransitionEnd() {
}
// 点击子项
function handleClick() {
async function handleClick() {
if (props.disabled) return
let name = props.name
const nexexpanded = !expanded.value // 执行后展开状态
if (nexexpanded) {
if (props.beforeExpend) {
const response: any = props.beforeExpend(name)
try {
await updateExpand()
const { name } = props
collapse && collapse.toggle(name, !expanded.value)
} catch (error) {
/* empty */
}
}
/**
* 展开前钩子
*/
function handleBeforeExpand() {
return new Promise<void>((resolve, reject) => {
const { name } = props
const nextexpanded = !expanded.value
if (nextexpanded && props.beforeExpend) {
const response = props.beforeExpend(name)
if (!response) {
return
reject()
}
if (isPromise(response)) {
response.then(() => {
handleChangeExpand(name)
})
response
.then(() => {
resolve()
})
.catch(() => {
reject()
})
} else {
handleChangeExpand(name)
resolve()
}
} else {
handleChangeExpand(name)
resolve()
}
} else {
handleChangeExpand(name)
}
})
}
function getExpanded() {
return expanded.value
}
function handleChangeExpand(name: string) {
updateExpand()
collapse && collapse.toggle(name, !expanded.value)
}
defineExpose<CollapseItemExpose>({ getExpanded, updateExpand })
</script>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export type CollapseExpose = {
* 切换所有面板展开状态,传 true 为全部展开,false 为全部收起,不传参为全部切换
* @param options 面板状态
*/
toggleAll: (options?: boolean | CollapseToggleAllOptions) => void
toggleAll: (options?: CollapseToggleAllOptions) => void
}

export type CollapseInstance = ComponentPublicInstance<CollapseProps, CollapseExpose>
Loading

0 comments on commit b5e7e65

Please sign in to comment.