Skip to content

fix(panel): fix issues #219 #222

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Mar 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 19 additions & 15 deletions packages/devui-vue/devui/panel/src/body/panel-body.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,28 @@
import { defineComponent,ref,onMounted,Transition,inject,Ref } from 'vue';
import { defineComponent, ref, onMounted, Transition, inject, Ref } from 'vue';
import { PanelProps } from '../panel.type';
import Store from '../store/store';

export default defineComponent({
name: 'DPanelBody',
props:PanelProps,
setup(props,ctx){
props: PanelProps,
setup(props, ctx) {
const animationName = inject('showAnimation') as Ref<any>;
const hasLeftPadding = inject('hasLeftPadding') as Ref<any>;
const keys = Object.keys(Store.state());
const key = keys.pop();
const isCollapsed = Store.state();
const bodyEl = ref();
onMounted(() => {
if(bodyEl.value) {
if (bodyEl.value) {
const dom = bodyEl.value;
if(isCollapsed[key])
{dom.style.height = `${dom.offsetHeight}px`;}
if (isCollapsed[key as string]) {
dom.style.height = `${dom.offsetHeight}px`;
}
}
});

const enter = (element: Element) => {
const el = (element as HTMLElement);
const el = element as HTMLElement;
el.style.height = '';
const height = el.offsetHeight;
el.style.height = '0px';
Expand All @@ -30,19 +31,22 @@ export default defineComponent({
el.style.height = `${height}px`;
};
const leave = (element: Element) => {
const el = (element as HTMLElement);
const el = element as HTMLElement;
el.style.height = '0px';
};
return () => {
return (
<div class={`devui-panel devui-panel-${props.type} ${props.cssClass}`}>
<Transition name={animationName.value ? 'devui-panel' : ''} onEnter={ enter } onLeave={leave}>
{isCollapsed[key] === undefined || isCollapsed[key] ?
<div ref={bodyEl} class={`devui-panel-body ${isCollapsed[key] !== undefined ? 'devui-panel-body-collapse': ''} ${!hasLeftPadding.value ? 'no-left-padding' : ''}`}>
<div class="devui-panel-content">
{ctx.slots.default?.()}
</div>
</div>: null }
<Transition name={animationName.value ? 'devui-panel' : ''} onEnter={enter} onLeave={leave}>
{isCollapsed[key as string] === undefined || isCollapsed[key as string] ? (
<div
ref={bodyEl}
class={`devui-panel-body ${isCollapsed[key as string] !== undefined ? 'devui-panel-body-collapse' : ''} ${
!hasLeftPadding.value ? 'no-left-padding' : ''
}`}>
<div class='devui-panel-content'>{ctx.slots.default?.()}</div>
</div>
) : null}
</Transition>
</div>
);
Expand Down
2 changes: 1 addition & 1 deletion packages/devui-vue/devui/panel/src/foot/panel-footer.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {ref,defineComponent} from 'vue';
import {defineComponent} from 'vue';

export default defineComponent({
name: 'DPanelFooter',
Expand Down
63 changes: 38 additions & 25 deletions packages/devui-vue/devui/panel/src/header/panel-header.tsx
Original file line number Diff line number Diff line change
@@ -1,60 +1,73 @@
import { defineComponent,ref,inject } from 'vue';
/* eslint-disable @typescript-eslint/no-explicit-any */
import { defineComponent,ref,inject,Ref } from 'vue';
import {PanelProps} from '../panel.type';
import Store from '../store/store';

export default defineComponent({
name: 'DPanelHeader',
props: PanelProps,
emits: ['toggle'],
setup(props,ctx){
const beforeToggle = inject('beforeToggle');
const keys = Object.keys(Store.state());
const key = keys.pop();
const isCollapsed = ref(Store.state()[key]);
// 当beforeToggle为fals时
// 最好cursor是default 而不是 pointer;
// pointer一般用于可点击的
// 用changeFlag
const isCollapsed = ref(Store.state()[key as string]) as Ref<boolean>;
const changeFlag = ref();
let header = null;


const canToggle = (): Promise<boolean> => {
let changeResult = Promise.resolve(true);
if(beforeToggle) {
const result = beforeToggle(isCollapsed);
if(typeof result !== undefined) {
if(result instanceof Promise) {
changeResult = result;
let header: JSX.Element | null = null;
const res = ref(isCollapsed.value) as Ref<boolean>;
let changeResult = true;
const done = () => {
res.value = !res.value;
if (!changeFlag.value){
// 禁止折叠不影响展开
if (res.value){
Store.setData(`${key}`, res.value);
isCollapsed.value = res.value;
ctx.emit('toggle', res.value);
}
return;
}
if (res.value !== undefined) {
Store.setData(`${key}`, res.value);
isCollapsed.value = res.value;
ctx.emit('toggle', res.value);
}
};
const canToggle = async (): Promise<boolean> => {
if (beforeToggle){
const tmpRes = (beforeToggle as (value: Ref<boolean>,
done?: () => void) => any)(isCollapsed, done);
if (typeof tmpRes !== 'undefined'){
if (tmpRes instanceof Promise){
changeResult = (await tmpRes);
} else {
changeResult = Promise.resolve(result);
changeResult = tmpRes;
}
} else {
changeResult = true;
}
}
return changeResult;
};

// 需要执行一次才能生效;
canToggle().then((val)=>changeFlag.value = val);

canToggle().then(val => changeFlag.value = val);
const toggleBody = (): void => {
canToggle().then((val) => {
canToggle().then((val)=>{
changeFlag.value = val;
if (!val){
// 禁止折叠不影响展开
if (!isCollapsed.value){
Store.setData(`${key}`, !isCollapsed.value);
isCollapsed.value = !isCollapsed.value;
props.toggle?.(isCollapsed.value);
ctx.emit('toggle', isCollapsed.value);
}
return;
}
if (isCollapsed.value !== undefined) {
Store.setData(`${key}`, !isCollapsed.value);
isCollapsed.value = !isCollapsed.value;
props.toggle?.(isCollapsed.value);
ctx.emit('toggle', isCollapsed.value);
}
});

};
return () => {
if (ctx.slots.default){
Expand Down
5 changes: 3 additions & 2 deletions packages/devui-vue/devui/panel/src/panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,18 @@ import Store from './store/store';
export default defineComponent({
name: 'DPanel',
props: PanelProps,
emits: ['toggle'],
setup(props, ctx) {
provide('beforeToggle', props.beforeToggle);
provide('showAnimation', computed(()=>props.showAnimation));
provide('hasLeftPadding', computed(()=>props.hasLeftPadding));
const isCollapsed = ref(props.isCollapsed);
const type = computed(()=>props.type);
const cssClass = computed(()=>props.cssClass);
const timeStamp = new Date().getTime().toString() + Math.random();
const onToggle = ()=> {
props.toggle?.(Store.getByKey(`isCollapsed[${timeStamp}]`));
ctx.emit('toggle', Store.getByKey(`isCollapsed[${timeStamp}]`));
};
const timeStamp = new Date().getTime().toString();
Store.setData(`isCollapsed[${timeStamp}]`, isCollapsed.value);
return () => {
return (
Expand Down
6 changes: 1 addition & 5 deletions packages/devui-vue/devui/panel/src/panel.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,7 @@ export const PanelProps = {
default: false
},
beforeToggle: {
type: Function as unknown as () => (value: boolean) => boolean | Promise<boolean>,
default: null
},
toggle: {
type: Function as unknown as () => ((value: boolean) => void),
type: Function as unknown as () => (value: boolean, done?: () => void) => any,
default: null
},
showAnimation: {
Expand Down
6 changes: 3 additions & 3 deletions packages/devui-vue/devui/panel/src/store/store.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import {ref,reactive} from 'vue';

export const option = reactive({});
export const option = reactive({}) as Record<string,unknown>;

class Store {
public static getByKey(timeStamp){
public static getByKey(timeStamp: string){
return option[timeStamp];
}
public static state() {
return option;
}
public static setData(key,value){
public static setData(key: string ,value: unknown){
option[key] = ref(value);
}
}
Expand Down
70 changes: 65 additions & 5 deletions packages/devui-vue/docs/components/panel/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ export default defineComponent({
<d-panel-header>Panel with info Type</d-panel-header>
<d-panel-body>This is body</d-panel-body>
</d-panel>
<br />
<br />
<d-panel type="primary" :is-collapsed="true" :show-animation="true">
<d-panel-header>Panel with Primary Type</d-panel-header>
<d-panel-body>This is body</d-panel-body>
Expand Down Expand Up @@ -104,7 +106,7 @@ export default defineComponent({
<d-panel
type="primary"
:has-left-padding="padding"
:toggle="handleToggle"
@toggle="handleToggle"
:before-toggle="beforeToggle"
:show-animation="showAnimation"
>
Expand All @@ -116,6 +118,7 @@ export default defineComponent({
</d-panel>
<br />
<br />
<span>当前状态: {{nowState}}</span><br />
<d-button @click="panelToggle = !panelToggle">
{{ panelToggle ? '阻止折叠' : '允许折叠' }}
</d-button>
Expand All @@ -131,11 +134,12 @@ export default defineComponent({
let showAnimation = ref(true);
let state;
let padding = ref(false);
let nowState = ref('收起');
const handleToggle = (e) => {
toggle.value = e;
nowState.value = toggle.value === true ? '展开' : '收起';
};
const beforeToggle = (e) => {
console.log(e);
return panelToggle.value;
};
return {
Expand All @@ -146,11 +150,67 @@ export default defineComponent({
isCollapsed,
handleToggle,
showAnimation,
padding
padding,
nowState
};
}
});
</script>
```

:::

在某些场景下,我们或许需要使用js来对Panel进行开合控制,尤其是异步时。我们可以使用beforeToggle中的```done```函数来对Panel进行开合处理。

案例中我们使用setTimeout来模拟异步任务控制Panel开合

:::demo

```vue
<template>
<d-panel
type="primary"
:before-toggle="beforeToggle"
:is-collapsed="false"
>
<d-panel-header>
1s之后自动打开
</d-panel-header>
<d-panel-body>This is body</d-panel-body>
</d-panel>
<br />
<br />
<d-button @click="handleClick">
试一试
</d-button>
</template>

<script>
import { defineComponent, ref } from 'vue';

export default defineComponent({
setup() {
let opened = false;
let beforeToggle = (e, done) => {
if (!opened){
setTimeout(()=>{
done();
},1000);
opened = true;
}
}
const handleClick = () => {
window.location.reload();
}
return {
beforeToggle,
handleClick
};
}
});
</script>


```

:::
Expand Down Expand Up @@ -200,8 +260,8 @@ export default defineComponent({
| is-collapsed | boolean | false | 可选,是否展开 |
| has-left-padding | boolean | true | 可选,是否显示左侧填充 |
| show-animation | boolean | true | 可选,是否展示动画 |
| before-toggle | Function\|Promise\|Observable | -- | 可选,面板折叠状态改变前的回调函数,返回 boolean 类型,返回 false 可以阻止面板改变折叠状态 根据条件阻止折叠 |
| toggle | Function | -- | 可选,面板当前状态的回调函数,返回 boolean 类型,返回 false 代表面板被收起,返回 true 代表面板展开 |
| before-toggle | () => (value: boolean, done?: () => void) => any | -- | 可选,面板折叠状态改变前的回调函数, 参数```value```代表当前状态,参数```done()```可以控制Panel开合 |
| @toggle | Function | -- | 可选,面板当前状态的回调函数,返回 boolean 类型,返回 false 代表面板被收起,返回 true 代表面板展开 |

### 接口&类型定义

Expand Down