import _defineProperty from 'babel-runtime/helpers/defineProperty'; import _classCallCheck from 'babel-runtime/helpers/classCallCheck'; import _createClass from 'babel-runtime/helpers/createClass'; import _possibleConstructorReturn from 'babel-runtime/helpers/possibleConstructorReturn'; import _inherits from 'babel-runtime/helpers/inherits'; import React from 'react'; import { createPortal } from 'react-dom'; import PropTypes from 'prop-types'; import classnames from 'classnames'; import { dataToArray, transitionEnd } from './utils'; var windowIsUndefined = typeof window === 'undefined'; var Drawer = function (_React$PureComponent) { _inherits(Drawer, _React$PureComponent); function Drawer(props) { _classCallCheck(this, Drawer); var _this = _possibleConstructorReturn(this, (Drawer.__proto__ || Object.getPrototypeOf(Drawer)).call(this, props)); _this.levelDom = []; _this.contextDom = null; _this.maskDom = null; _this.mousePos = null; _this.getParentAndLevelDom = function () { if (windowIsUndefined) { return; } var _this$props = _this.props, level = _this$props.level, getContainer = _this$props.getContainer; _this.levelDom = []; _this.parent = getContainer && document.querySelectorAll(getContainer)[0] || _this.container.parentNode; if (level === 'all') { var children = Array.prototype.slice.call(_this.parent.children); children.forEach(function (child) { if (child.nodeName !== 'SCRIPT' && child.nodeName !== 'STYLE' && child !== _this.container) { _this.levelDom.push(child); } }); } else if (level) { dataToArray(_this.props.level).forEach(function (key) { document.querySelectorAll(key).forEach(function (item) { _this.levelDom.push(item); }); }); } }; _this.trnasitionEnd = function (e) { var dom = e.target; dom.removeEventListener(transitionEnd, _this.trnasitionEnd); dom.style.transition = ''; }; _this.onTouchEnd = function (e, close) { if (_this.props.open !== undefined) { return; } if (e) { e.preventDefault(); } var open = close || _this.state.open; _this.isOpenChange = true; _this.setState({ open: !open }); }; _this.onMaskTouchEnd = function (e) { _this.props.onMaskClick(e); _this.onTouchEnd(e, true); }; _this.onIconTouchEnd = function (e) { _this.props.onHandleClick(e); _this.onTouchEnd(e); }; _this.onScrollTouchStart = function (e) { if (e.touches.length > 1) { return; } var touchs = e.touches[0]; _this.mousePos = { x: touchs.pageX, y: touchs.pageY }; }; _this.onScrollTouchEnd = function () { _this.mousePos = null; }; _this.getScollDom = function (dom) { var doms = []; var setScrollDom = function setScrollDom(d) { if (!d) { return; } if (d.scrollHeight > d.clientHeight || d.scrollWidth > d.clientWidth) { doms.push(d); } if (d !== _this.contextDom && d !== _this.maskDom) { setScrollDom(d.parentNode); } }; setScrollDom(dom); return doms[doms.length - 1]; }; _this.getIsHandleDom = function (dom) { if (dom.className === _this.props.className + '-handle') { return true; } if (dom.parentNode) { return _this.getIsHandleDom(dom.parentNode); } return false; }; _this.removeScroll = function (e) { if (!_this.props.showMask) { return; } var dom = e.target; var scrollDom = _this.getScollDom(dom); if (dom === _this.maskDom || _this.getIsHandleDom(dom) || !scrollDom) { e.preventDefault(); e.returnValue = false; return; } var y = e.deltaY; var x = e.deltaX; if (e.type === 'touchmove') { if (e.touches.length > 1 || !_this.mousePos) { return; } var touches = e.touches[0]; // 上滑为正,下滑为负 y = _this.mousePos.y - touches.pageY; x = _this.mousePos.x - touches.pageX; } // 竖向 var scrollTop = scrollDom.scrollTop; var height = scrollDom.clientHeight; var scrollHeight = scrollDom.scrollHeight; var isScrollY = scrollHeight - height > 2; var maxOrMinScrollY = isScrollY && (scrollTop <= 0 && y < 0 || scrollTop + height >= scrollHeight && y > 0); // 横向 var width = scrollDom.clientWidth; var scrollLeft = scrollDom.scrollLeft; var scrollWidth = scrollDom.scrollWidth; var isScrollX = scrollWidth - width > 2; var maxOrMinScrollX = scrollWidth - width > 2 && (scrollLeft <= 0 && x < 0 || scrollLeft + width >= scrollWidth && x > 0); if (!isScrollY && !isScrollX || maxOrMinScrollY || maxOrMinScrollX) { e.preventDefault(); e.returnValue = false; return; } }; _this.setLevelDomTransform = function (open, openTransition, placementName, value) { var _this$props2 = _this.props, placement = _this$props2.placement, levelTransition = _this$props2.levelTransition, onChange = _this$props2.onChange; _this.levelDom.forEach(function (dom) { if (_this.isOpenChange || openTransition) { dom.style.transition = levelTransition; dom.addEventListener(transitionEnd, _this.trnasitionEnd); } var placementPos = placement === 'left' || placement === 'top' ? value : -value; dom.style.transform = open ? placementName + '(' + placementPos + 'px)' : ''; }); // 处理 body 滚动 if (!windowIsUndefined) { if (open) { document.body.addEventListener('mousewheel', _this.removeScroll); document.body.addEventListener('touchmove', _this.removeScroll); } else { document.body.removeEventListener('mousewheel', _this.removeScroll); document.body.removeEventListener('touchmove', _this.removeScroll); } } if (onChange && _this.isOpenChange) { onChange(open); _this.isOpenChange = false; } }; _this.getChildToRender = function () { var _classnames; var open = _this.props.open !== undefined ? _this.props.open : _this.state.open; var _this$props3 = _this.props, className = _this$props3.className, prefixCls = _this$props3.prefixCls, style = _this$props3.style, placement = _this$props3.placement, children = _this$props3.children, handleChild = _this$props3.handleChild, handleStyle = _this$props3.handleStyle, showMask = _this$props3.showMask, maskStyle = _this$props3.maskStyle; var wrapperClassname = classnames(prefixCls, (_classnames = {}, _defineProperty(_classnames, prefixCls + '-' + placement, true), _defineProperty(_classnames, prefixCls + '-open', open), _defineProperty(_classnames, className, !!className), _classnames)); var value = _this.contextDom ? _this.contextDom.getBoundingClientRect()[placement === 'left' || placement === 'right' ? 'width' : 'height'] : 0; var placementName = 'translate' + (placement === 'left' || placement === 'right' ? 'X' : 'Y'); // 百分比与像素动画不同步,第一次打用后全用像素动画。 var defaultValue = !_this.contextDom ? '100%' : value + 'px'; var placementPos = placement === 'left' || placement === 'top' ? '-' + defaultValue : defaultValue; var transform = open ? '' : placementName + '(' + placementPos + ')'; if (_this.isOpenChange === undefined || _this.isOpenChange) { _this.setLevelDomTransform(open, false, placementName, value); } return React.createElement( 'div', { className: wrapperClassname, style: style }, showMask && React.createElement('div', { className: prefixCls + '-mask', onClick: _this.onMaskTouchEnd, style: maskStyle, ref: function ref(c) { _this.maskDom = c; } }), React.createElement( 'div', { className: prefixCls + '-content-wrapper', style: { transform: transform } }, React.createElement( 'div', { className: prefixCls + '-content', onTouchStart: _this.onScrollTouchStart, onTouchEnd: _this.onScrollTouchEnd, ref: function ref(c) { _this.contextDom = c; } }, children ), handleChild && React.createElement( 'div', { className: prefixCls + '-handle', onClick: _this.onIconTouchEnd, style: handleStyle }, handleChild ) ) ); }; _this.defaultGetContainer = function () { if (windowIsUndefined) { return null; } var container = document.createElement('div'); _this.parent.appendChild(container); if (_this.props.wrapperClassName) { container.className = _this.props.wrapperClassName; } return container; }; if (props.onIconClick || props.parent || props.iconChild || props.width) { console.warn('rc-drawer-menu API has been changed, please look at the releases, ' + 'https://github.com/react-component/drawer-menu/releases'); } _this.state = { open: props.open !== undefined ? props.open : !!props.defaultOpen }; return _this; } _createClass(Drawer, [{ key: 'componentDidMount', value: function componentDidMount() { this.getParentAndLevelDom(); if (this.props.getContainer || this.props.parent) { this.container = this.defaultGetContainer(); } this.forceUpdate(); } }, { key: 'componentWillReceiveProps', value: function componentWillReceiveProps(nextProps) { var open = nextProps.open, placement = nextProps.placement, children = nextProps.children; if (open !== undefined && open !== this.props.open) { this.isOpenChange = true; this.setState({ open: open }); } if (placement !== this.props.placement || children !== this.props.children) { // test 的 bug, 有动画过场,删除 dom this.contextDom = null; } } }, { key: 'componentWillUnmount', value: function componentWillUnmount() { if (this.container) { this.setLevelDomTransform(false, true); // 拦不住。。直接删除; if (this.props.getContainer) { this.container.parentNode.removeChild(this.container); } } } }, { key: 'render', value: function render() { var _this2 = this; var children = this.getChildToRender(); if (!this.props.getContainer) { return React.createElement( 'div', { className: this.props.wrapperClassName, ref: function ref(c) { _this2.container = c; } }, children ); } if (!this.container) { return null; } return createPortal(children, this.container); } }]); return Drawer; }(React.PureComponent); Drawer.propTypes = { wrapperClassName: PropTypes.string, open: PropTypes.bool, bodyStyle: PropTypes.object, defaultOpen: PropTypes.bool, placement: PropTypes.string, level: PropTypes.oneOfType([PropTypes.string, PropTypes.array]), levelTransition: PropTypes.string, getContainer: PropTypes.string, handleChild: PropTypes.any, handleStyle: PropTypes.object, onChange: PropTypes.func, onMaskClick: PropTypes.func, onHandleClick: PropTypes.func, showMask: PropTypes.bool, maskStyle: PropTypes.object }; Drawer.defaultProps = { className: '', prefixCls: 'drawer', placement: 'left', getContainer: 'body', level: 'all', levelTransition: 'transform .3s cubic-bezier(0.78, 0.14, 0.15, 0.86)', onChange: function onChange() {}, onMaskClick: function onMaskClick() {}, onHandleClick: function onHandleClick() {}, handleChild: React.createElement('i', { className: 'drawer-handle-icon' }), handleStyle: {}, showMask: true, maskStyle: {} }; export default Drawer;