Skip to content

Commit 2f80207

Browse files
kagolgitee-org
authored andcommitted
!235 fix(panel): 修复了动态属性无法动态切换的bug
Merge pull request !235 from EditorWang/dev
2 parents 062ee74 + 0be8381 commit 2f80207

File tree

7 files changed

+280
-94
lines changed

7 files changed

+280
-94
lines changed
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
import { shallowMount,mount } from "@vue/test-utils";
2+
import {ref,nextTick,Transition } from 'vue';
3+
import DButton from '../../button/index';
4+
import DPanel from '../src/panel'
5+
import DPanelHeader from '../src/header/panel-header';
6+
import DPanelBody from '../src/body/panel-body';
7+
import DPanelFooter from '../src/foot/panel-footer';
8+
9+
10+
describe('DPanel',()=>{
11+
12+
// 渲染测试
13+
it('Render',()=>{
14+
// except(wrapper.html())
15+
let wrapper = mount({
16+
components:{
17+
DPanel,
18+
DPanelBody,
19+
DPanelHeader,
20+
DPanelFooter,
21+
DButton
22+
},
23+
template: `
24+
<d-panel>
25+
<d-panel-header>
26+
Panel with foldable
27+
</d-panel-header>
28+
<d-panel-body>
29+
This is body
30+
</d-panel-body>
31+
</d-panel>
32+
`,
33+
});
34+
expect(wrapper.find('transition-stub').html()).toContain('<transition-stub><!----></transition-stub>');
35+
})
36+
37+
it('isCollapsed', async ()=>{
38+
let wrapper = mount({
39+
components:{
40+
DPanel,
41+
DPanelBody,
42+
DPanelHeader,
43+
DPanelFooter,
44+
DButton
45+
},
46+
template: `
47+
<d-panel :isCollapsed="isCollapsed">
48+
<d-panel-header>
49+
Panel with foldable
50+
</d-panel-header>
51+
<d-panel-body>
52+
This is body
53+
</d-panel-body>
54+
</d-panel>
55+
`,
56+
setup(){
57+
let isCollapsed = ref(false);
58+
return {isCollapsed}
59+
}
60+
});
61+
expect(wrapper.find('.devui-panel .devui-panel-default').element.children[0].innerHTML).toBe('<!---->');
62+
})
63+
// // 动态hasLeftPadding 测试
64+
it('padding-dynamic', async ()=>{
65+
let wrapper = mount({
66+
components:{
67+
DPanel,
68+
DPanelBody,
69+
DPanelHeader,
70+
DPanelFooter,
71+
DButton
72+
},
73+
template: `
74+
<d-panel :hasLeftPadding = "leftPadding" isCollapsed>
75+
<d-panel-header>
76+
Panel with foldable
77+
</d-panel-header>
78+
<d-panel-body>
79+
This is body
80+
</d-panel-body>
81+
</d-panel>
82+
<br /><br />
83+
<d-button @click="leftPadding = !leftPadding" >
84+
切换LeftPadding
85+
</d-button>
86+
`,
87+
setup(){
88+
let leftPadding = ref(false);
89+
return {
90+
leftPadding,
91+
}
92+
}
93+
});
94+
expect(wrapper.find('.devui-panel-body-collapse').classes().length).toBe(3);
95+
await wrapper.find('button').trigger('click');
96+
expect(wrapper.find('.devui-panel-body-collapse').classes().length).toBe(2);
97+
})
98+
99+
100+
it('beforeToggle-dynamic',async ()=>{
101+
let wrapper = mount({
102+
components:{
103+
DPanel,
104+
DPanelBody,
105+
DPanelHeader,
106+
DPanelFooter,
107+
DButton
108+
},
109+
template: `
110+
<d-panel :beforeToggle="beforeToggle" isCollapsed>
111+
<d-panel-header>
112+
Panel with foldable
113+
</d-panel-header>
114+
<d-panel-body>
115+
This is body
116+
</d-panel-body>
117+
</d-panel>
118+
<br /><br />
119+
<d-button @click="panelToggle = !panelToggle" >
120+
{{ panelToggle ? '阻止折叠' : '允许折叠' }}
121+
</d-button>
122+
`,
123+
setup(){
124+
let panelToggle = ref(false);
125+
const beforeToggle = () => panelToggle.value;
126+
return {
127+
panelToggle,
128+
beforeToggle,
129+
}
130+
}
131+
});
132+
await wrapper.find('button').trigger('click');
133+
expect(wrapper.vm.panelToggle).toBe(true);
134+
await wrapper.find('button').trigger('click');
135+
expect(wrapper.vm.panelToggle).toBe(false);
136+
})
137+
})

devui/panel/src/body/panel-body.tsx

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
1-
import { defineComponent,ref,onMounted,Transition,inject } from 'vue';
1+
import { defineComponent,ref,onMounted,Transition,inject,Ref } from 'vue';
22
import { PanelProps } from '../panel.type';
33
import Store from '../store/store';
44

55
export default defineComponent({
66
name: 'DPanelBody',
77
props:PanelProps,
88
setup(props,ctx){
9-
const animationName = inject('showAnimation') ? 'devui-panel' : '';
10-
const hasLeftPadding = !inject('hasLeftPadding') ? 'no-left-padding' : '';
11-
9+
let animationName = inject('showAnimation') as Ref<any>;
10+
let hasLeftPadding = inject('hasLeftPadding') as Ref<any>;
1211
const keys = Object.keys(Store.state());
1312
const key = keys.pop();
1413
const isCollapsed = Store.state();
@@ -34,13 +33,12 @@ export default defineComponent({
3433
const el = (element as HTMLElement);
3534
el.style.height = '0px';
3635
}
37-
3836
return () => {
3937
return (
4038
<div class={`devui-panel devui-panel-${props.type} ${props.cssClass}`}>
41-
<Transition name={animationName} onEnter={ enter } onLeave={leave}>
39+
<Transition name={animationName.value ? 'devui-panel' : ''} onEnter={ enter } onLeave={leave}>
4240
{isCollapsed[key] === undefined || isCollapsed[key] ?
43-
<div ref={bodyEl} class={`devui-panel-body ${isCollapsed[key] !== undefined ? 'devui-panel-body-collapse': ''} ${hasLeftPadding}`}>
41+
<div ref={bodyEl} class={`devui-panel-body ${isCollapsed[key] !== undefined ? 'devui-panel-body-collapse': ''} ${!hasLeftPadding.value ? 'no-left-padding' : ''}`}>
4442
<div class="devui-panel-content">
4543
{ctx.slots.default?.()}
4644
</div>

devui/panel/src/header/panel-header.tsx

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,40 +10,56 @@ export default defineComponent({
1010
const keys = Object.keys(Store.state());
1111
const key = keys.pop();
1212
const isCollapsed = ref(Store.state()[key]);
13+
// 当beforeToggle为fals时
14+
// 最好cursor是default 而不是 pointer;
15+
// pointer一般用于可点击的
16+
// 用changeFlag
17+
let changeFlag = ref();
18+
let header = null;
19+
1320

1421
const canToggle = (): Promise<boolean> => {
15-
let changeResult = Promise.resolve(true);
16-
if(beforeToggle) {
17-
const result = beforeToggle(isCollapsed);
18-
if(typeof result !== undefined) {
19-
if(result instanceof Promise) {
20-
changeResult = result;
21-
} else {
22-
changeResult = Promise.resolve(result);
23-
}
22+
let changeResult = Promise.resolve(true);
23+
if(beforeToggle) {
24+
const result = beforeToggle(isCollapsed);
25+
if(typeof result !== undefined) {
26+
if(result instanceof Promise) {
27+
changeResult = result;
28+
} else {
29+
changeResult = Promise.resolve(result);
2430
}
2531
}
26-
return changeResult;
2732
}
28-
29-
const toggleBody = (): void => {
30-
canToggle().then((val) => {
31-
if (!val){
32-
return;
33-
}
34-
if (isCollapsed.value !== undefined) {
33+
return changeResult;
34+
}
35+
36+
// 需要执行一次才能生效;
37+
canToggle().then((val)=>changeFlag.value = val)
38+
39+
const toggleBody = (): void => {
40+
canToggle().then((val) => {
41+
changeFlag.value = val;
42+
if (!val){
43+
// 禁止折叠不影响展开
44+
if (!isCollapsed.value){
3545
Store.setData(`${key}`, !isCollapsed.value);
3646
isCollapsed.value = !isCollapsed.value;
3747
props.toggle?.(isCollapsed.value);
3848
}
39-
})
40-
41-
};
49+
return;
50+
}
51+
if (isCollapsed.value !== undefined) {
52+
Store.setData(`${key}`, !isCollapsed.value);
53+
isCollapsed.value = !isCollapsed.value;
54+
props.toggle?.(isCollapsed.value);
55+
}
56+
})
57+
58+
};
4259
return () => {
43-
let header = null;
4460
if (ctx.slots.default){
4561
header = (
46-
<div class="devui-panel-heading" onClick={toggleBody} style={{ 'cursor': isCollapsed.value !== undefined ? 'pointer' : 'auto' }}>
62+
<div class="devui-panel-heading" onClick={toggleBody} style={{ 'cursor': changeFlag.value ? 'pointer' : 'auto' }}>
4763
{ctx.slots.default?.()}
4864
</div>
4965
)

devui/panel/src/panel.scss

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
@import '../../style/theme/color';
22

3+
.no-left-padding {
4+
&.devui-panel-body-collapse {
5+
&::before {
6+
content: none !important;
7+
}
8+
9+
.devui-panel-content {
10+
border-left: none !important;
11+
}
12+
}
13+
}
14+
315
.devui-panel {
416
line-height: 1.5;
517
background-color: $devui-base-bg;
@@ -13,17 +25,6 @@
1325
}
1426
}
1527

16-
.no-left-padding {
17-
&.devui-panel-body-collapse {
18-
&::before {
19-
display: none;
20-
}
21-
22-
.devui-panel-content {
23-
border-left: none !important;
24-
}
25-
}
26-
}
2728

2829
.devui-panel-body {
2930
display: flex;

devui/panel/src/panel.tsx

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { defineComponent, ref, Transition, onMounted, provide } from 'vue';
1+
import { defineComponent, ref, provide, computed} from 'vue';
22
import './panel.scss';
33
import { PanelProps } from './panel.type';
44
import Store from './store/store';
@@ -8,31 +8,22 @@ export default defineComponent({
88
props: PanelProps,
99
setup(props, ctx) {
1010
provide('beforeToggle', props.beforeToggle);
11-
provide('showAnimation', props.showAnimation);
12-
provide('hasLeftPadding', props.hasLeftPadding);
11+
provide('showAnimation', computed(()=>props.showAnimation));
12+
provide('hasLeftPadding', computed(()=>props.hasLeftPadding));
1313
const isCollapsed = ref(props.isCollapsed);
14-
const bodyEl = ref();
14+
const type = computed(()=>props.type);
15+
const cssClass = computed(()=>props.cssClass);
1516
const onToggle = ()=> {
1617
props.toggle?.(Store.getByKey(`isCollapsed[${timeStamp}]`))
1718
};
18-
19-
onMounted(() => {
20-
if(bodyEl.value) {
21-
const dom = bodyEl.value;
22-
if(isCollapsed.value)
23-
dom.style.height = `${dom.offsetHeight}px`;
24-
}
25-
})
26-
2719
const timeStamp = new Date().getTime().toString();
2820
Store.setData(`isCollapsed[${timeStamp}]`, isCollapsed.value);
29-
3021
return () => {
3122
return (
32-
<div onClick = {onToggle} class={`devui-panel devui-panel-${props.type} ${props.cssClass}`}>
33-
{ctx.slots.default()}
23+
<div onClick = {onToggle} class={`devui-panel devui-panel-${type.value} ${cssClass.value}`}>
24+
{ctx.slots.default?.()}
3425
</div>
3526
)
3627
}
37-
},
28+
}
3829
})

devui/panel/src/panel.type.ts

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,34 @@ import {ExtractPropTypes} from 'vue';
33
export type PanelType = 'default' | 'primary' | 'success' | 'danger' | 'warning' | 'info';
44

55
export const PanelProps = {
6-
type: {
7-
type: String as () => PanelType,
8-
default: 'default'
9-
},
10-
cssClass: {
11-
type: String,
12-
default: ''
13-
},
14-
isCollapsed: {
15-
type: Boolean,
16-
default: undefined
17-
},
18-
beforeToggle: {
19-
type: Function as unknown as () => (value: boolean) => boolean | Promise<boolean>,
20-
default: null
21-
},
22-
toggle: {
23-
type: Function as unknown as ()=> ((value: boolean) => void),
24-
default: null
25-
},
26-
showAnimation: {
27-
type: Boolean,
28-
default: true,
29-
},
30-
hasLeftPadding:{
31-
type: Boolean,
32-
default: true,
33-
}
6+
type: {
7+
type: String as () => PanelType,
8+
default: 'default'
9+
},
10+
cssClass: {
11+
type: String,
12+
default: ''
13+
},
14+
isCollapsed: {
15+
type: Boolean,
16+
default: false
17+
},
18+
beforeToggle: {
19+
type: Function as unknown as () => (value: boolean) => boolean | Promise<boolean>,
20+
default: null
21+
},
22+
toggle: {
23+
type: Function as unknown as ()=> ((value: boolean) => void),
24+
default: null
25+
},
26+
showAnimation: {
27+
type: Boolean,
28+
default: true,
29+
},
30+
hasLeftPadding:{
31+
type: Boolean,
32+
default: true,
33+
}
3434
}
3535

3636
export type PanelPropsType = ExtractPropTypes<typeof PanelProps>;

0 commit comments

Comments
 (0)