fix: body scroll when open modal #1472

pull/1534/head
tangjinzhou 2019-12-09 22:23:40 +08:00
parent c86a261bca
commit e4f83939b9
5 changed files with 56 additions and 66 deletions

View File

@ -4,7 +4,7 @@ exports[`Modal render correctly 1`] = `
<div> <div>
<div> <div>
<div> <div>
<div> <div class="ant-modal-root">
<div class="ant-modal-mask"></div> <div class="ant-modal-mask"></div>
<div tabindex="-1" role="dialog" class="ant-modal-wrap "> <div tabindex="-1" role="dialog" class="ant-modal-wrap ">
<div role="document" class="ant-modal" style="width: 520px;"> <div role="document" class="ant-modal" style="width: 520px;">
@ -29,7 +29,7 @@ exports[`Modal render correctly 2`] = `
<div> <div>
<div> <div>
<div> <div>
<div> <div class="ant-modal-root">
<div class="ant-modal-mask"></div> <div class="ant-modal-mask"></div>
<div tabindex="-1" role="dialog" class="ant-modal-wrap "> <div tabindex="-1" role="dialog" class="ant-modal-wrap ">
<div role="document" class="ant-modal" style="width: 520px;"> <div role="document" class="ant-modal" style="width: 520px;">
@ -54,7 +54,7 @@ exports[`Modal render without footer 1`] = `
<div> <div>
<div> <div>
<div> <div>
<div> <div class="ant-modal-root">
<div class="ant-modal-mask"></div> <div class="ant-modal-mask"></div>
<div tabindex="-1" role="dialog" class="ant-modal-wrap "> <div tabindex="-1" role="dialog" class="ant-modal-wrap ">
<div role="document" class="ant-modal" style="width: 520px;"> <div role="document" class="ant-modal" style="width: 520px;">

View File

@ -46,6 +46,8 @@ function offset(el) {
return pos; return pos;
} }
let cacheOverflow = {};
export default { export default {
mixins: [BaseMixin], mixins: [BaseMixin],
props: initDefaultProps(IDialogPropTypes, { props: initDefaultProps(IDialogPropTypes, {
@ -57,6 +59,7 @@ export default {
destroyOnClose: false, destroyOnClose: false,
prefixCls: 'rc-dialog', prefixCls: 'rc-dialog',
getOpenCount: () => null, getOpenCount: () => null,
focusTriggerAfterClose: true,
}), }),
data() { data() {
return { return {
@ -81,16 +84,6 @@ export default {
}, },
}, },
// private inTransition: boolean;
// private titleId: string;
// private openTime: number;
// private lastOutSideFocusNode: HTMLElement | null;
// private wrap: HTMLElement;
// private dialog: any;
// private sentinel: HTMLElement;
// private bodyIsOverflowing: boolean;
// private scrollbarWidth: number;
beforeMount() { beforeMount() {
this.inTransition = false; this.inTransition = false;
this.titleId = `rcDialogTitle${uuid++}`; this.titleId = `rcDialogTitle${uuid++}`;
@ -107,7 +100,7 @@ export default {
beforeDestroy() { beforeDestroy() {
const { visible, getOpenCount } = this; const { visible, getOpenCount } = this;
if ((visible || this.inTransition) && !getOpenCount()) { if ((visible || this.inTransition) && !getOpenCount()) {
this.removeScrollingEffect(); this.switchScrollingEffect();
} }
clearTimeout(this.timeoutId); clearTimeout(this.timeoutId);
}, },
@ -118,12 +111,13 @@ export default {
}, },
updatedCallback(visible) { updatedCallback(visible) {
const mousePosition = this.mousePosition; const mousePosition = this.mousePosition;
const {mask, focusTriggerAfterClose} = this;
if (this.visible) { if (this.visible) {
// first show // first show
if (!visible) { if (!visible) {
this.openTime = Date.now(); this.openTime = Date.now();
// this.lastOutSideFocusNode = document.activeElement // this.lastOutSideFocusNode = document.activeElement
this.addScrollingEffect(); this.switchScrollingEffect();
// this.$refs.wrap.focus() // this.$refs.wrap.focus()
this.tryFocus(); this.tryFocus();
const dialogNode = this.$refs.dialog.$el; const dialogNode = this.$refs.dialog.$el;
@ -139,7 +133,7 @@ export default {
} }
} else if (visible) { } else if (visible) {
this.inTransition = true; this.inTransition = true;
if (this.mask && this.lastOutSideFocusNode) { if (mask && this.lastOutSideFocusNode && focusTriggerAfterClose) {
try { try {
this.lastOutSideFocusNode.focus(); this.lastOutSideFocusNode.focus();
} catch (e) { } catch (e) {
@ -166,7 +160,7 @@ export default {
this.destroyPopup = true; this.destroyPopup = true;
} }
this.inTransition = false; this.inTransition = false;
this.removeScrollingEffect(); this.switchScrollingEffect();
if (afterClose) { if (afterClose) {
afterClose(); afterClose();
} }
@ -224,6 +218,7 @@ export default {
bodyStyle, bodyStyle,
visible, visible,
bodyProps, bodyProps,
forceRender,
} = this; } = this;
const dest = {}; const dest = {};
if (width !== undefined) { if (width !== undefined) {
@ -284,6 +279,7 @@ export default {
ref="dialog" ref="dialog"
style={style} style={style}
class={cls} class={cls}
forceRender={forceRender}
onMousedown={this.onDialogMouseDown} onMousedown={this.onDialogMouseDown}
> >
<div tabIndex={0} ref="sentinelStart" style={sentinelStyle} aria-hidden="true" /> <div tabIndex={0} ref="sentinelStart" style={sentinelStyle} aria-hidden="true" />
@ -369,60 +365,50 @@ export default {
// document.body.style.paddingRight = `${this.scrollbarWidth}px`; // document.body.style.paddingRight = `${this.scrollbarWidth}px`;
// } // }
// }, // },
addScrollingEffect() { switchScrollingEffect() {
const { getOpenCount } = this; const { getOpenCount } = this;
const openCount = getOpenCount(); const openCount = getOpenCount();
if (openCount !== 1) { if (openCount === 1) {
return; if (cacheOverflow.hasOwnProperty('overflowX')) {
return;
}
cacheOverflow = {
overflowX: document.body.style.overflowX,
overflowY: document.body.style.overflowY,
overflow: document.body.style.overflow,
};
switchScrollingEffect();
// Must be set after switchScrollingEffect
document.body.style.overflow = 'hidden';
} else if (!openCount) {
// IE browser doesn't merge overflow style, need to set it separately
// https://github.com/ant-design/ant-design/issues/19393
if (cacheOverflow.overflow !== undefined) {
document.body.style.overflow = cacheOverflow.overflow;
}
if (cacheOverflow.overflowX !== undefined) {
document.body.style.overflowX = cacheOverflow.overflowX;
}
if (cacheOverflow.overflowY !== undefined) {
document.body.style.overflowY = cacheOverflow.overflowY;
}
cacheOverflow = {};
switchScrollingEffect(true);
} }
switchScrollingEffect();
document.body.style.overflow = 'hidden';
},
removeScrollingEffect() {
const { getOpenCount } = this;
const openCount = getOpenCount();
if (openCount !== 0) {
return;
}
document.body.style.overflow = '';
switchScrollingEffect(true);
// this.resetAdjustments();
}, },
// removeScrollingEffect() {
// const { getOpenCount } = this;
// const openCount = getOpenCount();
// if (openCount !== 0) {
// return;
// }
// document.body.style.overflow = '';
// switchScrollingEffect(true);
// // this.resetAdjustments();
// },
close(e) { close(e) {
this.__emit('close', e); this.__emit('close', e);
}, },
// checkScrollbar() {
// let fullWindowWidth = window.innerWidth;
// if (!fullWindowWidth) {
// // workaround for missing window.innerWidth in IE8
// const documentElementRect = document.documentElement.getBoundingClientRect();
// fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left);
// }
// this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth;
// if (this.bodyIsOverflowing) {
// this.scrollbarWidth = getScrollBarSize();
// }
// },
// resetScrollbar() {
// document.body.style.paddingRight = '';
// },
// adjustDialog() {
// if (this.$refs.wrap && this.scrollbarWidth !== undefined) {
// const modalIsOverflowing =
// this.$refs.wrap.scrollHeight > document.documentElement.clientHeight;
// this.$refs.wrap.style.paddingLeft = `${
// !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : ''
// }px`;
// this.$refs.wrap.style.paddingRight = `${
// this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''
// }px`;
// }
// },
// resetAdjustments() {
// if (this.$refs.wrap) {
// this.$refs.wrap.style.paddingLeft = this.$refs.wrap.style.paddingLeft = '';
// }
// },
}, },
render() { render() {
const { prefixCls, maskClosable, visible, wrapClassName, title, wrapProps } = this; const { prefixCls, maskClosable, visible, wrapClassName, title, wrapProps } = this;
@ -433,7 +419,7 @@ export default {
style.display = null; style.display = null;
} }
return ( return (
<div> <div class={`${prefixCls}-root`}>
{this.getMaskElement()} {this.getMaskElement()}
<div <div
tabIndex={-1} tabIndex={-1}

View File

@ -37,6 +37,9 @@ function IDialogPropTypes() {
closeIcon: PropTypes.any, closeIcon: PropTypes.any,
forceRender: PropTypes.bool, forceRender: PropTypes.bool,
getOpenCount: PropTypes.func, getOpenCount: PropTypes.func,
// https://github.com/ant-design/ant-design/issues/19771
// https://github.com/react-component/dialog/issues/95
focusTriggerAfterClose: PropTypes.bool,
}; };
} }

View File

@ -3,6 +3,7 @@ import PropTypes from '../_util/vue-types';
const ILazyRenderBoxPropTypes = { const ILazyRenderBoxPropTypes = {
visible: PropTypes.bool, visible: PropTypes.bool,
hiddenClassName: PropTypes.string, hiddenClassName: PropTypes.string,
forceRender: PropTypes.bool,
}; };
export default { export default {

View File

@ -1,3 +1,3 @@
// based on vc-dialog 7.5.5 // based on vc-dialog 7.5.14
import DialogWrap from './DialogWrap'; import DialogWrap from './DialogWrap';
export default DialogWrap; export default DialogWrap;