refactor(drawer): update

refactor-drawer
ajuner 2021-09-27 17:44:19 +08:00 committed by tangjinzhou
parent 0c31ada67a
commit 85ce6b6e24
7 changed files with 82 additions and 668 deletions

View File

@ -38,14 +38,14 @@ const MultiDrawer = {
width: 520,
visible: this.visible,
getContainer: false,
wrapClassName: 'test_drawer',
className: 'test_drawer',
placement: this.placement,
onClose: this.onClose,
};
const childrenDrawerProps = {
title: 'Two-level Drawer',
width: 320,
wrapClassName: 'Two-level',
className: 'Two-level',
visible: this.childrenDrawer,
getContainer: false,
placement: this.placement,
@ -112,7 +112,7 @@ describe('Drawer', () => {
wrapper.find('#open_two_drawer').trigger('click');
}, 0);
await asyncExpect(() => {
const translateX = wrapper.find('.ant-drawer.test_drawer').element.style.transform;
const translateX = wrapper.find('.test_drawer').find('.ant-drawer').element.style.transform;
expect(translateX).toEqual('translateX(-180px)');
expect(wrapper.find('#two_drawer_text').exists()).toBe(true);
}, 1000);
@ -133,7 +133,7 @@ describe('Drawer', () => {
wrapper.find('#open_two_drawer').trigger('click');
}, 0);
await asyncExpect(() => {
const translateX = wrapper.find('.ant-drawer.test_drawer').element.style.transform;
const translateX = wrapper.find('.test_drawer').find('.ant-drawer').element.style.transform;
expect(translateX).toEqual('translateX(180px)');
expect(wrapper.find('#two_drawer_text').exists()).toBe(true);
}, 1000);
@ -153,7 +153,7 @@ describe('Drawer', () => {
wrapper.find('#open_two_drawer').trigger('click');
}, 0);
await asyncExpect(() => {
const translateY = wrapper.find('.ant-drawer.test_drawer').element.style.transform;
const translateY = wrapper.find('.test_drawer').find('.ant-drawer').element.style.transform;
expect(translateY).toEqual('translateY(180px)');
expect(wrapper.find('#two_drawer_text').exists()).toBe(true);
}, 1000);

View File

@ -1,110 +1,122 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Drawer class is test_drawer 1`] = `
<div class="">
<div class="ant-drawer ant-drawer-right test_drawer" tabindex="-1">
<div>
<div class="ant-drawer ant-drawer-right" tabindex="-1">
<div class="ant-drawer-mask"></div>
<div class="ant-drawer-content-wrapper" style="transform: translateX(100%); width: 256px;">
<div class="ant-drawer-content-wrapper" style="transform: translateX(100%); width: 378px;">
<div class="ant-drawer-content">
<div class="ant-drawer-wrapper-body">
<div class="ant-drawer-header-no-title">
<!----><button aria-label="Close" class="ant-drawer-close"><span role="img" aria-label="close" class="anticon anticon-close"><svg focusable="false" class="" data-icon="close" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"></path></svg></span></button>
<div class="ant-drawer-header ant-drawer-header-close-only">
<div class="ant-drawer-header-title"><button aria-label="Close" class="ant-drawer-close"><span role="img" aria-label="close" class="anticon anticon-close"><svg focusable="false" class="" data-icon="close" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"></path></svg></span></button>
<!---->
</div>
<!---->
</div>
<div class="ant-drawer-body">Here is content of Drawer</div>
<!---->
</div>
</div>
<!---->
</div>
</div>
</div>
`;
exports[`Drawer closable is false 1`] = `
<div class="">
<div class="ant-drawer ant-drawer-right" tabindex="-1">
<div>
<div class="ant-drawer ant-drawer-right ant-drawer-open" tabindex="-1">
<div class="ant-drawer-mask"></div>
<div class="ant-drawer-content-wrapper" style="transform: translateX(100%); width: 256px;">
<div class="ant-drawer-content-wrapper" style="width: 378px;">
<div class="ant-drawer-content">
<div class="ant-drawer-wrapper-body">
<!---->
<div class="ant-drawer-body">Here is content of Drawer</div>
<!---->
</div>
</div>
<!---->
</div>
</div>
</div>
`;
exports[`Drawer destroyOnClose is true 1`] = `
<div class="">
<div>
<div class="ant-drawer ant-drawer-right" tabindex="-1">
<div class="ant-drawer-mask"></div>
<div class="ant-drawer-content-wrapper" style="transform: translateX(100%); width: 256px;">
<div class="ant-drawer-content-wrapper" style="transform: translateX(100%); width: 378px;">
<div class="ant-drawer-content">
<div class="ant-drawer-wrapper-body" style="opacity: 0; transition: opacity .3s;">
<!---->
<div class="ant-drawer-body">Here is content of Drawer</div>
<!---->
</div>
</div>
<!---->
</div>
</div>
</div>
`;
exports[`Drawer have a title 1`] = `
<div class="">
<div class="ant-drawer ant-drawer-right" tabindex="-1">
<div>
<div class="ant-drawer ant-drawer-right ant-drawer-open" tabindex="-1">
<div class="ant-drawer-mask"></div>
<div class="ant-drawer-content-wrapper" style="transform: translateX(100%); width: 256px;">
<div class="ant-drawer-content-wrapper" style="width: 378px;">
<div class="ant-drawer-content">
<div class="ant-drawer-wrapper-body">
<div class="ant-drawer-header">
<div class="ant-drawer-title">Test Title</div><button aria-label="Close" class="ant-drawer-close"><span role="img" aria-label="close" class="anticon anticon-close"><svg focusable="false" class="" data-icon="close" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"></path></svg></span></button>
<div class="ant-drawer-header-title"><button aria-label="Close" class="ant-drawer-close"><span role="img" aria-label="close" class="anticon anticon-close"><svg focusable="false" class="" data-icon="close" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"></path></svg></span></button>
<div class="ant-drawer-title">Test Title</div>
</div>
<!---->
</div>
<div class="ant-drawer-body">Here is content of Drawer</div>
<!---->
</div>
</div>
<!---->
</div>
</div>
</div>
`;
exports[`Drawer render correctly 1`] = `
<div class="">
<div class="ant-drawer ant-drawer-right" tabindex="-1">
<div>
<div class="ant-drawer ant-drawer-right ant-drawer-open" tabindex="-1">
<div class="ant-drawer-mask"></div>
<div class="ant-drawer-content-wrapper" style="transform: translateX(100%); width: 400px;">
<div class="ant-drawer-content-wrapper" style="width: 400px;">
<div class="ant-drawer-content">
<div class="ant-drawer-wrapper-body">
<div class="ant-drawer-header-no-title">
<!----><button aria-label="Close" class="ant-drawer-close"><span role="img" aria-label="close" class="anticon anticon-close"><svg focusable="false" class="" data-icon="close" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"></path></svg></span></button>
<div class="ant-drawer-header ant-drawer-header-close-only">
<div class="ant-drawer-header-title"><button aria-label="Close" class="ant-drawer-close"><span role="img" aria-label="close" class="anticon anticon-close"><svg focusable="false" class="" data-icon="close" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"></path></svg></span></button>
<!---->
</div>
<!---->
</div>
<div class="ant-drawer-body">Here is content of Drawer</div>
<!---->
</div>
</div>
<!---->
</div>
</div>
</div>
`;
exports[`Drawer render top drawer 1`] = `
<div class="">
<div class="ant-drawer ant-drawer-top" tabindex="-1">
<div>
<div class="ant-drawer ant-drawer-top ant-drawer-open" tabindex="-1">
<div class="ant-drawer-mask"></div>
<div class="ant-drawer-content-wrapper" style="transform: translateY(-100%); height: 400px;">
<div class="ant-drawer-content-wrapper" style="height: 400px;">
<div class="ant-drawer-content">
<div class="ant-drawer-wrapper-body">
<div class="ant-drawer-header-no-title">
<!----><button aria-label="Close" class="ant-drawer-close"><span role="img" aria-label="close" class="anticon anticon-close"><svg focusable="false" class="" data-icon="close" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"></path></svg></span></button>
<div class="ant-drawer-header ant-drawer-header-close-only">
<div class="ant-drawer-header-title"><button aria-label="Close" class="ant-drawer-close"><span role="img" aria-label="close" class="anticon anticon-close"><svg focusable="false" class="" data-icon="close" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"></path></svg></span></button>
<!---->
</div>
<!---->
</div>
<div class="ant-drawer-body">Here is content of Drawer</div>
<!---->
</div>
</div>
<!---->
</div>
</div>
</div>

View File

@ -4,19 +4,22 @@ exports[`Drawer render correctly 1`] = `
<div><button class="ant-btn" type="button" ant-click-animating-without-extra-node="false">
<!----><span>open</span>
</button>
<div class="">
<div>
<div class="ant-drawer ant-drawer-right" tabindex="-1">
<div class="ant-drawer-mask"></div>
<div class="ant-drawer-content-wrapper" style="transform: translateX(100%); width: 256px;">
<div class="ant-drawer-content-wrapper" style="transform: translateX(100%); width: 378px;">
<div class="ant-drawer-content">
<div class="ant-drawer-wrapper-body">
<div class="ant-drawer-header-no-title">
<!----><button aria-label="Close" class="ant-drawer-close"><span role="img" aria-label="close" class="anticon anticon-close"><svg focusable="false" class="" data-icon="close" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"></path></svg></span></button>
<div class="ant-drawer-header ant-drawer-header-close-only">
<div class="ant-drawer-header-title"><button aria-label="Close" class="ant-drawer-close"><span role="img" aria-label="close" class="anticon anticon-close"><svg focusable="false" class="" data-icon="close" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"></path></svg></span></button>
<!---->
</div>
<!---->
</div>
<div class="ant-drawer-body">Here is content of Drawer</div>
<!---->
</div>
</div>
<!---->
</div>
</div>
</div>

View File

@ -7,6 +7,13 @@ exports[`renders ./components/drawer/demo/basic.vue correctly 1`] = `
<!---->
`;
exports[`renders ./components/drawer/demo/extra.vue correctly 1`] = `
<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default" style="margin-right: 8px;"><label class="ant-radio-wrapper"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="top"><span class="ant-radio-inner"></span></span><span>top</span></label><label class="ant-radio-wrapper"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="right"><span class="ant-radio-inner"></span></span><span>right</span></label><label class="ant-radio-wrapper"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="bottom"><span class="ant-radio-inner"></span></span><span>bottom</span></label><label class="ant-radio-wrapper ant-radio-wrapper-checked"><span class="ant-radio ant-radio-checked"><input type="radio" class="ant-radio-input" value="left"><span class="ant-radio-inner"></span></span><span>left</span></label></div><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Open</span>
</button>
<!---->
`;
exports[`renders ./components/drawer/demo/form-in-drawer.vue correctly 1`] = `
<button class="ant-btn ant-btn-primary" type="button">
<!----><span role="img" aria-label="plus" class="anticon anticon-plus"><svg focusable="false" class="" data-icon="plus" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><defs><style></style></defs><path d="M482 152h60q8 0 8 8v704q0 8-8 8h-60q-8 0-8-8V160q0-8 8-8z"></path><path d="M176 474h672q8 0 8 8v60q0 8-8 8H176q-8 0-8-8v-60q0-8 8-8z"></path></svg></span><span>New account</span>
@ -32,28 +39,40 @@ exports[`renders ./components/drawer/demo/render-in-current.vue correctly 1`] =
<div style="height: 200px; overflow: hidden; position: relative; border: 1px solid #ebedf0; border-radius: 2px; padding: 48px; text-align: center; background: rgb(250, 250, 250); width: 100%;"> Render in this <div style="margin-top: 16px;"><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Open</span>
</button></div>
<div class="">
<div class="ant-drawer ant-drawer-right" style="position: absolute;" tabindex="-1">
<div>
<div class="ant-drawer ant-drawer-right" tabindex="-1" style="position: absolute;">
<div class="ant-drawer-mask"></div>
<div class="ant-drawer-content-wrapper" style="transform: translateX(100%); width: 256px;">
<div class="ant-drawer-content-wrapper" style="transform: translateX(100%); width: 378px;">
<div class="ant-drawer-content">
<div class="ant-drawer-wrapper-body">
<div class="ant-drawer-header">
<div class="ant-drawer-title">Basic Drawer</div>
<div class="ant-drawer-header-title">
<!---->
<div class="ant-drawer-title">Basic Drawer</div>
</div>
<!---->
</div>
<div class="ant-drawer-body">
<p>Some contents...</p>
</div>
<!---->
</div>
</div>
<!---->
</div>
</div>
</div>
</div>
`;
exports[`renders ./components/drawer/demo/size.vue correctly 1`] = `
<button class="ant-btn ant-btn-primary" type="button">
<!----><span>Open Default Size (378px)</span>
</button><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Open Large Size (736px)</span>
</button>
<!---->
`;
exports[`renders ./components/drawer/demo/user-profile.vue correctly 1`] = `
<div class="ant-list ant-list-split ant-list-bordered">
<!---->

View File

@ -37,19 +37,19 @@ Open a new drawer on top of an existing drawer to handle multi branch tasks.
<template>
<a-button type="primary" @click="showDrawer">Open</a-button>
<a-drawer
v-model:visible="visible"
title="Multi-level drawer"
width="520"
:closable="false"
v-model:visible="visible"
:footer-style="{ textAlign: 'right' }"
@close="onClose"
>
<a-button type="primary" @click="showChildrenDrawer">Two-level drawer</a-button>
<a-drawer
v-model:visible="childrenDrawer"
title="Two-level Drawer"
width="320"
:closable="false"
v-model:visible="childrenDrawer"
>
<a-button type="primary" @click="showChildrenDrawer">This is two-level drawer</a-button>
</a-drawer>

View File

@ -1,620 +0,0 @@
import classnames from '../../_util/classNames';
import { Teleport, nextTick, defineComponent } from 'vue';
import BaseMixin from '../../_util/BaseMixin';
import { initDefaultProps, getSlot } from '../../_util/props-util';
import getScrollBarSize from '../../_util/getScrollBarSize';
import { IDrawerProps } from './IDrawerPropTypes';
import KeyCode from '../../_util/KeyCode';
import {
dataToArray,
transitionEnd,
transitionStr,
addEventListener,
removeEventListener,
transformArguments,
isNumeric,
} from './utils';
import supportsPassive from '../../_util/supportsPassive';
import { cloneElement } from '../../_util/vnode';
function noop() {}
const currentDrawer = {};
const windowIsUndefined = !(
typeof window !== 'undefined' &&
window.document &&
window.document.createElement
);
const Drawer = defineComponent({
name: 'Drawer',
mixins: [BaseMixin],
inheritAttrs: false,
props: initDefaultProps(IDrawerProps, {
prefixCls: 'drawer',
placement: 'left',
getContainer: 'body',
level: 'all',
duration: '.3s',
ease: 'cubic-bezier(0.78, 0.14, 0.15, 0.86)',
firstEnter: false, // .
showMask: true,
handler: true,
maskStyle: {},
wrapperClassName: '',
}),
data() {
this.levelDom = [];
this.contentDom = null;
this.maskDom = null;
this.handlerdom = null;
this.mousePos = null;
this.sFirstEnter = this.firstEnter;
this.timeout = null;
this.children = null;
this.dom = null;
this.drawerId = Number(
(Date.now() + Math.random()).toString().replace('.', Math.round(Math.random() * 9)),
).toString(16);
const open = this.open !== undefined ? this.open : !!this.defaultOpen;
currentDrawer[this.drawerId] = open;
this.orignalOpen = this.open;
this.preProps = { ...this.$props };
return {
sOpen: open,
isOpenChange: undefined,
passive: undefined,
container: undefined,
};
},
watch: {
open(val) {
if (val !== undefined && val !== this.preProps.open) {
this.isOpenChange = true;
// dom ;
if (!this.container) {
this.getDefault(this.$props);
}
this.setState({
sOpen: open,
});
}
this.preProps.open = val;
if (val) {
setTimeout(() => {
this.domFocus();
});
}
},
placement(val) {
if (val !== this.preProps.placement) {
// test bug, dom
this.contentDom = null;
}
this.preProps.placement = val;
},
level(val) {
if (this.preProps.level !== val) {
this.getParentAndLevelDom(this.$props);
}
this.preProps.level = val;
},
},
mounted() {
nextTick(() => {
if (!windowIsUndefined) {
this.passive = supportsPassive ? { passive: false } : false;
}
const open = this.getOpen();
if (this.handler || open || this.sFirstEnter) {
this.getDefault(this.$props);
if (open) {
this.isOpenChange = true;
nextTick(() => {
this.domFocus();
});
}
this.$forceUpdate();
}
});
},
updated() {
nextTick(() => {
// dom
if (!this.sFirstEnter && this.container) {
this.$forceUpdate();
this.sFirstEnter = true;
}
});
},
beforeUnmount() {
delete currentDrawer[this.drawerId];
delete this.isOpenChange;
if (this.container) {
if (this.sOpen) {
this.setLevelDomTransform(false, true);
}
document.body.style.overflow = '';
}
this.sFirstEnter = false;
clearTimeout(this.timeout);
},
methods: {
domFocus() {
if (this.dom) {
this.dom.focus();
}
},
onKeyDown(e) {
if (e.keyCode === KeyCode.ESC) {
e.stopPropagation();
this.__emit('close', e);
}
},
onMaskTouchEnd(e) {
this.__emit('close', e);
this.onTouchEnd(e, true);
},
onIconTouchEnd(e) {
this.__emit('handleClick', e);
this.onTouchEnd(e);
},
onTouchEnd(e, close) {
if (this.open !== undefined) {
return;
}
const open = close || this.sOpen;
this.isOpenChange = true;
this.setState({
sOpen: !open,
});
},
onWrapperTransitionEnd(e) {
if (e.target === this.contentWrapper && e.propertyName.match(/transform$/)) {
const open = this.getOpen();
this.dom.style.transition = '';
if (!open && this.getCurrentDrawerSome()) {
document.body.style.overflowX = '';
if (this.maskDom) {
this.maskDom.style.left = '';
this.maskDom.style.width = '';
}
}
if (this.afterVisibleChange) {
this.afterVisibleChange(!!open);
}
}
},
getDefault(props) {
this.getParentAndLevelDom(props);
if (props.getContainer || props.parent) {
this.container = this.defaultGetContainer();
}
},
getCurrentDrawerSome() {
return !Object.keys(currentDrawer).some(key => currentDrawer[key]);
},
getSelfContainer() {
return this.container;
},
getParentAndLevelDom(props) {
if (windowIsUndefined) {
return;
}
const { level, getContainer } = props;
this.levelDom = [];
if (getContainer) {
if (typeof getContainer === 'string') {
const dom = document.querySelectorAll(getContainer)[0];
this.parent = dom;
}
if (typeof getContainer === 'function') {
this.parent = getContainer();
}
if (typeof getContainer === 'object' && getContainer instanceof window.HTMLElement) {
this.parent = getContainer;
}
}
if (!getContainer && this.container) {
this.parent = this.container.parentNode;
}
if (level === 'all') {
const children = Array.prototype.slice.call(this.parent.children);
children.forEach(child => {
if (
child.nodeName !== 'SCRIPT' &&
child.nodeName !== 'STYLE' &&
child.nodeName !== 'LINK' &&
child !== this.container
) {
this.levelDom.push(child);
}
});
} else if (level) {
dataToArray(level).forEach(key => {
document.querySelectorAll(key).forEach(item => {
this.levelDom.push(item);
});
});
}
},
setLevelDomTransform(open, openTransition, placementName, value) {
const { placement, levelMove, duration, ease, getContainer } = this.$props;
if (!windowIsUndefined) {
this.levelDom.forEach(dom => {
if (dom && (this.isOpenChange || openTransition)) {
/* eslint no-param-reassign: "error" */
dom.style.transition = `transform ${duration} ${ease}`;
addEventListener(dom, transitionEnd, this.trnasitionEnd);
let levelValue = open ? value : 0;
if (levelMove) {
const $levelMove = transformArguments(levelMove, { target: dom, open });
levelValue = open ? $levelMove[0] : $levelMove[1] || 0;
}
const $value = typeof levelValue === 'number' ? `${levelValue}px` : levelValue;
const placementPos =
placement === 'left' || placement === 'top' ? $value : `-${$value}`;
dom.style.transform = levelValue ? `${placementName}(${placementPos})` : '';
dom.style.msTransform = levelValue ? `${placementName}(${placementPos})` : '';
}
});
// body
if (getContainer === 'body') {
const eventArray = ['touchstart'];
const domArray = [document.body, this.maskDom, this.handlerdom, this.contentDom];
const right =
document.body.scrollHeight >
(window.innerHeight || document.documentElement.clientHeight) &&
window.innerWidth > document.body.offsetWidth
? getScrollBarSize(1)
: 0;
let widthTransition = `width ${duration} ${ease}`;
const trannsformTransition = `transform ${duration} ${ease}`;
if (open && document.body.style.overflow !== 'hidden') {
document.body.style.overflow = 'hidden';
if (right) {
document.body.style.position = 'relative';
document.body.style.width = `calc(100% - ${right}px)`;
clearTimeout(this.timeout);
if (this.dom) {
this.dom.style.transition = 'none';
switch (placement) {
case 'right':
this.dom.style.transform = `translateX(-${right}px)`;
this.dom.style.msTransform = `translateX(-${right}px)`;
break;
case 'top':
case 'bottom':
this.dom.style.width = `calc(100% - ${right}px)`;
this.dom.style.transform = 'translateZ(0)';
break;
default:
break;
}
this.timeout = setTimeout(() => {
this.dom.style.transition = `${trannsformTransition},${widthTransition}`;
this.dom.style.width = '';
this.dom.style.transform = '';
this.dom.style.msTransform = '';
});
}
}
//
domArray.forEach((item, i) => {
if (!item) {
return;
}
addEventListener(
item,
eventArray[i] || 'touchmove',
i ? this.removeMoveHandler : this.removeStartHandler,
this.passive,
);
});
} else if (this.getCurrentDrawerSome()) {
document.body.style.overflow = '';
if ((this.isOpenChange || openTransition) && right) {
document.body.style.position = '';
document.body.style.width = '';
if (transitionStr) {
document.body.style.overflowX = 'hidden';
}
if (placement === 'right' && this.maskDom) {
this.maskDom.style.left = `-${right}px`;
this.maskDom.style.width = `calc(100% + ${right}px)`;
}
clearTimeout(this.timeout);
if (this.dom) {
this.dom.style.transition = 'none';
let heightTransition;
switch (placement) {
case 'right': {
this.dom.style.transform = `translateX(${right}px)`;
this.dom.style.msTransform = `translateX(${right}px)`;
this.dom.style.width = '100%';
widthTransition = `width 0s ${ease} ${duration}`;
break;
}
case 'top':
case 'bottom': {
this.dom.style.width = `calc(100% + ${right}px)`;
this.dom.style.height = '100%';
this.dom.style.transform = 'translateZ(0)';
heightTransition = `height 0s ${ease} ${duration}`;
break;
}
default:
break;
}
this.timeout = setTimeout(() => {
this.dom.style.transition = `${trannsformTransition},${
heightTransition ? `${heightTransition},` : ''
}${widthTransition}`;
this.dom.style.transform = '';
this.dom.style.msTransform = '';
this.dom.style.width = '';
this.dom.style.height = '';
});
}
}
domArray.forEach((item, i) => {
if (!item) {
return;
}
removeEventListener(
item,
eventArray[i] || 'touchmove',
i ? this.removeMoveHandler : this.removeStartHandler,
this.passive,
);
});
}
}
}
const { onChange } = this.$attrs;
if (onChange && this.isOpenChange && this.sFirstEnter) {
onChange(open);
this.isOpenChange = false;
}
},
getChildToRender(open) {
const {
prefixCls,
placement,
handler,
showMask,
maskStyle,
width,
height,
wrapStyle,
keyboard,
maskClosable,
} = this.$props;
const { class: cls, style, ...restAttrs } = this.$attrs;
const children = getSlot(this);
const wrapperClassname = classnames(prefixCls, {
[`${prefixCls}-${placement}`]: true,
[`${prefixCls}-open`]: open,
'no-mask': !showMask,
[cls]: cls,
});
const isOpenChange = this.isOpenChange;
const isHorizontal = placement === 'left' || placement === 'right';
const placementName = `translate${isHorizontal ? 'X' : 'Y'}`;
//
// const defaultValue = !this.contentDom || !level ? '100%' : `${value}px`;
const placementPos = placement === 'left' || placement === 'top' ? '-100%' : '100%';
const transform = open ? '' : `${placementName}(${placementPos})`;
if (isOpenChange === undefined || isOpenChange) {
const contentValue = this.contentDom
? this.contentDom.getBoundingClientRect()[isHorizontal ? 'width' : 'height']
: 0;
const value = (isHorizontal ? width : height) || contentValue;
this.setLevelDomTransform(open, false, placementName, value);
}
let handlerChildren;
if (handler !== false) {
const handlerDefalut = (
<div class="drawer-handle" onClick={() => {}}>
<i class="drawer-handle-icon" />
</div>
);
const { handler: handlerSlot } = this;
const handlerSlotVnode = handlerSlot || handlerDefalut;
const handleIconClick = handlerSlotVnode.props && handlerSlotVnode.props.onClick;
handlerChildren = cloneElement(handlerSlotVnode, {
onClick: e => {
handleIconClick && handleIconClick(e);
this.onIconTouchEnd(e);
},
ref: c => {
this.handlerdom = c;
},
});
}
const domContProps = {
...restAttrs,
class: wrapperClassname,
onTransitionend: this.onWrapperTransitionEnd,
onKeydown: open && keyboard ? this.onKeyDown : noop,
style: { ...wrapStyle, ...style },
};
//
const touchEvents = {
[supportsPassive ? 'onTouchstartPassive' : 'onTouchstart']: open
? this.removeStartHandler
: noop,
[supportsPassive ? 'onTouchmovePassive' : 'onTouchmove']: open
? this.removeMoveHandler
: noop,
};
return (
<div
ref={c => {
this.dom = c;
}}
{...domContProps}
tabindex={-1}
>
{showMask && (
<div
key={open} // 第二次渲染时虚拟DOM没有改变没有出发dom更新使用key强制更新 https://github.com/vueComponent/ant-design-vue/issues/2407
class={`${prefixCls}-mask`}
onClick={maskClosable ? this.onMaskTouchEnd : noop}
style={maskStyle}
ref={c => {
this.maskDom = c;
}}
/>
)}
<div
class={`${prefixCls}-content-wrapper`}
style={{
transform,
msTransform: transform,
width: isNumeric(width) ? `${width}px` : width,
height: isNumeric(height) ? `${height}px` : height,
}}
ref={c => {
this.contentWrapper = c;
}}
>
<div
class={`${prefixCls}-content`}
ref={c => {
this.contentDom = c;
}}
{...touchEvents}
>
{children}
</div>
{handlerChildren}
</div>
</div>
);
},
getOpen() {
return this.open !== undefined ? this.open : this.sOpen;
},
getTouchParentScroll(root, currentTarget, differX, differY) {
if (!currentTarget || currentTarget === document) {
return false;
}
// root drawer-content overflow, root parent
if (currentTarget === root.parentNode) {
return true;
}
const isY = Math.max(Math.abs(differX), Math.abs(differY)) === Math.abs(differY);
const isX = Math.max(Math.abs(differX), Math.abs(differY)) === Math.abs(differX);
const scrollY = currentTarget.scrollHeight - currentTarget.clientHeight;
const scrollX = currentTarget.scrollWidth - currentTarget.clientWidth;
/**
* <div style="height: 300px">
* <div style="height: 900px"></div>
* </div>
* 在没设定 overflow: auto scroll currentTarget 里获取不到 scrollTop scrollLeft,
* 预先用 scrollTo 来滚动如果取出的值跟滚动前取出不同 currnetTarget 被设定了 overflow; 否则就是上面这种
*/
const t = currentTarget.scrollTop;
const l = currentTarget.scrollLeft;
if (currentTarget.scrollTo) {
currentTarget.scrollTo(currentTarget.scrollLeft + 1, currentTarget.scrollTop + 1);
}
const currentT = currentTarget.scrollTop;
const currentL = currentTarget.scrollLeft;
if (currentTarget.scrollTo) {
currentTarget.scrollTo(currentTarget.scrollLeft - 1, currentTarget.scrollTop - 1);
}
if (
(isY &&
(!scrollY ||
!(currentT - t) ||
(scrollY &&
((currentTarget.scrollTop >= scrollY && differY < 0) ||
(currentTarget.scrollTop <= 0 && differY > 0))))) ||
(isX &&
(!scrollX ||
!(currentL - l) ||
(scrollX &&
((currentTarget.scrollLeft >= scrollX && differX < 0) ||
(currentTarget.scrollLeft <= 0 && differX > 0)))))
) {
return this.getTouchParentScroll(root, currentTarget.parentNode, differX, differY);
}
return false;
},
removeStartHandler(e) {
if (e.touches.length > 1) {
return;
}
this.startPos = {
x: e.touches[0].clientX,
y: e.touches[0].clientY,
};
},
removeMoveHandler(e) {
if (e.changedTouches.length > 1) {
return;
}
const currentTarget = e.currentTarget;
const differX = e.changedTouches[0].clientX - this.startPos.x;
const differY = e.changedTouches[0].clientY - this.startPos.y;
if (
currentTarget === this.maskDom ||
currentTarget === this.handlerdom ||
(currentTarget === this.contentDom &&
this.getTouchParentScroll(currentTarget, e.target, differX, differY))
) {
e.preventDefault();
}
},
trnasitionEnd(e) {
removeEventListener(e.target, transitionEnd, this.trnasitionEnd);
e.target.style.transition = '';
},
defaultGetContainer() {
if (windowIsUndefined) {
return null;
}
const container = document.createElement('div');
this.parent.appendChild(container);
if (this.wrapperClassName) {
container.className = this.wrapperClassName;
}
return container;
},
},
render() {
const { getContainer, wrapperClassName, handler, forceRender } = this.$props;
const open = this.getOpen();
let portal = null;
currentDrawer[this.drawerId] = open ? this.container : open;
const children = this.getChildToRender(this.sFirstEnter ? open : false);
if (!getContainer) {
return (
<div
class={wrapperClassName}
ref={c => {
this.container = c;
}}
>
{children}
</div>
);
}
if (!this.container || (!open && !this.sFirstEnter)) {
return null;
}
// handler
const $forceRender = !!handler || forceRender;
if ($forceRender || open || this.dom) {
portal = <Teleport to={this.getSelfContainer()}>{children}</Teleport>;
}
return portal;
},
});
export default Drawer;

View File

@ -1,5 +1,5 @@
import PropTypes from '../../_util/vue-types';
import { PropType, ExtractPropTypes } from 'vue';
import type { PropType, ExtractPropTypes } from 'vue';
export type IPlacement = 'left' | 'top' | 'right' | 'bottom';