无木
2021-06-27 941ad59759cbd5a5e39bcdf29783d8eea85caf72
提交 | 用户 | age
ebf7c8 1 <template>
V 2   <Drawer :class="prefixCls" @close="onClose" v-bind="getBindValues">
3     <template #title v-if="!$slots.title">
4       <DrawerHeader
5         :title="getMergeProps.title"
6         :isDetail="isDetail"
7         :showDetailBack="showDetailBack"
8         @close="onClose"
9       >
10         <template #titleToolbar>
9edc28 11           <slot name="titleToolbar"></slot>
ebf7c8 12         </template>
V 13       </DrawerHeader>
14     </template>
b9b470 15     <template v-else #title>
V 16       <slot name="title"></slot>
17     </template>
ebf7c8 18
V 19     <ScrollContainer
20       :style="getScrollContentStyle"
21       v-loading="getLoading"
efbde0 22       :loading-tip="loadingText || t('common.loadingText')"
ebf7c8 23     >
9edc28 24       <slot></slot>
ebf7c8 25     </ScrollContainer>
V 26     <DrawerFooter v-bind="getProps" @close="onClose" @ok="handleOk" :height="getFooterHeight">
27       <template #[item]="data" v-for="item in Object.keys($slots)">
9edc28 28         <slot :name="item" v-bind="data"></slot>
ebf7c8 29       </template>
V 30     </DrawerFooter>
31   </Drawer>
32 </template>
33 <script lang="ts">
c7c95d 34   import type { DrawerInstance, DrawerProps } from './typing';
ebf7c8 35   import type { CSSProperties } from 'vue';
V 36   import {
37     defineComponent,
38     ref,
39     computed,
40     watch,
41     unref,
42     nextTick,
43     toRaw,
44     getCurrentInstance,
45   } from 'vue';
46   import { Drawer } from 'ant-design-vue';
47   import { useI18n } from '/@/hooks/web/useI18n';
48   import { isFunction, isNumber } from '/@/utils/is';
49   import { deepMerge } from '/@/utils';
50   import DrawerFooter from './components/DrawerFooter.vue';
51   import DrawerHeader from './components/DrawerHeader.vue';
52   import { ScrollContainer } from '/@/components/Container';
53   import { basicProps } from './props';
54   import { useDesign } from '/@/hooks/web/useDesign';
55   import { useAttrs } from '/@/hooks/core/useAttrs';
56
57   export default defineComponent({
58     components: { Drawer, ScrollContainer, DrawerFooter, DrawerHeader },
9edc28 59     inheritAttrs: false,
ebf7c8 60     props: basicProps,
V 61     emits: ['visible-change', 'ok', 'close', 'register'],
62     setup(props, { emit }) {
63       const visibleRef = ref(false);
64       const attrs = useAttrs();
65       const propsRef = ref<Partial<Nullable<DrawerProps>>>(null);
66
67       const { t } = useI18n();
68       const { prefixVar, prefixCls } = useDesign('basic-drawer');
69
70       const drawerInstance: DrawerInstance = {
71         setDrawerProps: setDrawerProps,
72         emitVisible: undefined,
73       };
74
75       const instance = getCurrentInstance();
76
77       instance && emit('register', drawerInstance, instance.uid);
78
00fca0 79       const getMergeProps = computed((): DrawerProps => {
V 80         return deepMerge(toRaw(props), unref(propsRef));
81       });
ebf7c8 82
00fca0 83       const getProps = computed((): DrawerProps => {
V 84         const opt = {
85           placement: 'right',
86           ...unref(attrs),
87           ...unref(getMergeProps),
88           visible: unref(visibleRef),
89         };
90         opt.title = undefined;
91         const { isDetail, width, wrapClassName, getContainer } = opt;
92         if (isDetail) {
93           if (!width) {
94             opt.width = '100%';
ebf7c8 95           }
00fca0 96           const detailCls = `${prefixCls}__detail`;
V 97           opt.wrapClassName = wrapClassName ? `${wrapClassName} ${detailCls}` : detailCls;
ebf7c8 98
00fca0 99           if (!getContainer) {
V 100             // TODO type error?
101             opt.getContainer = `.${prefixVar}-layout-content` as any;
102           }
ebf7c8 103         }
00fca0 104         return opt as DrawerProps;
V 105       });
106
107       const getBindValues = computed((): DrawerProps => {
108         return {
109           ...attrs,
110           ...unref(getProps),
111         };
112       });
ebf7c8 113
V 114       // Custom implementation of the bottom button,
115       const getFooterHeight = computed(() => {
116         const { footerHeight, showFooter } = unref(getProps);
117         if (showFooter && footerHeight) {
118           return isNumber(footerHeight)
119             ? `${footerHeight}px`
120             : `${footerHeight.replace('px', '')}px`;
121         }
122         return `0px`;
123       });
124
00fca0 125       const getScrollContentStyle = computed((): CSSProperties => {
V 126         const footerHeight = unref(getFooterHeight);
127         return {
128           position: 'relative',
129           height: `calc(100% - ${footerHeight})`,
130         };
131       });
ebf7c8 132
V 133       const getLoading = computed(() => {
134         return !!unref(getProps)?.loading;
135       });
136
941ad5 137       watch(
138         () => props.visible,
139         (newVal, oldVal) => {
140           if (newVal != oldVal) visibleRef.value = newVal;
141         },
142         { deep: true }
143       );
ebf7c8 144
V 145       watch(
146         () => visibleRef.value,
147         (visible) => {
148           nextTick(() => {
149             emit('visible-change', visible);
150             instance && drawerInstance.emitVisible?.(visible, instance.uid);
151           });
152         }
153       );
154
155       // Cancel event
156       async function onClose(e: Recordable) {
157         const { closeFunc } = unref(getProps);
158         emit('close', e);
159         if (closeFunc && isFunction(closeFunc)) {
160           const res = await closeFunc();
161           visibleRef.value = !res;
162           return;
163         }
164         visibleRef.value = false;
165       }
166
167       function setDrawerProps(props: Partial<DrawerProps>): void {
168         // Keep the last setDrawerProps
fa828f 169         propsRef.value = deepMerge(unref(propsRef) || ({} as any), props);
ebf7c8 170
V 171         if (Reflect.has(props, 'visible')) {
172           visibleRef.value = !!props.visible;
173         }
174       }
175
176       function handleOk() {
177         emit('ok');
178       }
179
180       return {
181         onClose,
182         t,
183         prefixCls,
184         getMergeProps,
185         getScrollContentStyle,
186         getProps,
187         getLoading,
188         getBindValues,
189         getFooterHeight,
190         handleOk,
191       };
192     },
193   });
194 </script>
195 <style lang="less">
196   @header-height: 60px;
197   @detail-header-height: 40px;
198   @prefix-cls: ~'@{namespace}-basic-drawer';
199   @prefix-cls-detail: ~'@{namespace}-basic-drawer__detail';
200
201   .@{prefix-cls} {
202     .ant-drawer-wrapper-body {
203       overflow: hidden;
204     }
205
206     .ant-drawer-close {
207       &:hover {
208         color: @error-color;
209       }
210     }
211
212     .ant-drawer-body {
213       height: calc(100% - @header-height);
214       padding: 0;
5b8eb4 215       background-color: @component-background;
ebf7c8 216
V 217       .scrollbar__wrap {
218         padding: 16px !important;
219         margin-bottom: 0 !important;
220       }
354904 221
V 222       > .scrollbar > .scrollbar__bar.is-horizontal {
223         display: none;
224       }
ebf7c8 225     }
V 226   }
227
228   .@{prefix-cls-detail} {
229     position: absolute;
230
231     .ant-drawer-header {
232       width: 100%;
233       height: @detail-header-height;
234       padding: 0;
235       border-top: 1px solid @border-color-base;
236       box-sizing: border-box;
237     }
238
239     .ant-drawer-title {
240       height: 100%;
241     }
242
243     .ant-drawer-close {
244       height: @detail-header-height;
245       line-height: @detail-header-height;
246     }
247
248     .scrollbar__wrap {
249       padding: 0 !important;
250     }
251
252     .ant-drawer-body {
253       height: calc(100% - @detail-header-height);
254     }
255   }
256 </style>