UNPKG

jimu-mobile

Version:

积木组件库助力移动端开发

447 lines (386 loc) 12.5 kB
/** * Created by yanshenshen on 17/04/10. */ import React from 'react'; import classNames from 'classnames'; import ReactDOM from 'react-dom'; import PropTypes from 'prop-types'; import Swipe from '../swipe/index'; const { Swipeable } = Swipe; class SwipeMove extends React.Component { static propTypes = { direction: PropTypes.string, height: PropTypes.string, width: PropTypes.string, align: PropTypes.number, degree: PropTypes.number, } static defaultProps = { direction: 'bottom', // 滑动方向 bottom , top , left ,right height: '100%', // 高度 "100%" 、"300px" width: '100%', // 宽度 "100%" 、"300px" degree: 80, // 滑动展示最小值 align: 0, // 对齐方式 0: center、middle ,1:left 、top 2: right bottom back: null, // 滑动后的回调函数 } constructor(props) { super(props); this.swipingUp = this.swipingUp.bind(this); this.swipingDown = this.swipingDown.bind(this); this.swipingLeft = this.swipingLeft.bind(this); this.swipingRight = this.swipingRight.bind(this); this.swiped = this.swiped.bind(this); } componentDidMount() { this.initSetContentStyle(this.props); } componentWillReceiveProps(nextprops) { if (nextprops.direction !== this.props.direction || nextprops.height !== this.props.height || nextprops.width !== this.props.width || nextprops.align !== this.props.align) { this.initSetContentStyle(nextprops); } } // 设置 内容位置以及展开状态 setContState(pos, open) { const { touchContent } = this, { direction, back } = this.props, // { oldPosY, oldPosX } = this.state, self = this; touchContent.style.WebkitTransition = 'all 0.1s ease-in'; if (direction === 'bottom') { touchContent.style.top = `${pos}px`; } else if (direction === 'top') { touchContent.style.bottom = `${pos}px`; } else if (direction === 'left') { touchContent.style.right = `${pos}px`; } else { touchContent.style.left = `${pos}px`; } setTimeout(() => { if (direction === 'bottom' || direction === 'top') { self.setState({ open, oldPosY: pos, }); } else { self.setState({ open, oldPosX: pos, }); } // self.refs.touchScroll.style.overflow = "auto" }, 30); back && back({ open }); } swipingDown(e, posY) { const self = this, { touchContent, touchScroll, touchMain } = this, touchScrollTop = ReactDOM.findDOMNode(touchScroll).scrollTop, touchScrollHeight = ReactDOM.findDOMNode(touchScroll).clientHeight, touchMainHeight = ReactDOM.findDOMNode(touchMain).clientHeight, { distance, postion, open, contentHeight, } = this.state, { direction } = this.props; if (touchScrollTop + touchScrollHeight < touchMainHeight + 5 && direction !== 'bottom' && open || direction === 'left' || direction === 'right') { return; } if (touchScrollTop > 0 && direction === 'bottom' && open) { return; } // 阻止window窗体滚动 e.preventDefault && e.preventDefault(); if ((direction === 'bottom' && !open) || (direction === 'top' && open) || direction === 'left' || direction === 'right') { return false; } touchContent.style.WebkitTransition = 'none'; // this.refs.touchScroll.style.overflow = "hidden" // 弹层跟随坐标 if (direction === 'bottom') { touchContent.style.top = `${postion + posY}px`; } if (direction === 'top') { const ContposY = posY > contentHeight ? contentHeight : posY; touchContent.style.bottom = `${distance - ContposY}px`; } setTimeout(() => { self.setState({ oldPosY: posY, }); }, 30); } swipingLeft(e, posX) { const self = this, { touchContent } = this, { distance, postion, open, contentWidth, } = this.state, { direction } = this.props; if ((direction === 'left' && !open) || (direction === 'right' && open) || direction === 'bottom' || direction === 'up') { return false; } touchContent.style.WebkitTransition = 'none'; // 弹层跟随坐标 if (direction === 'left') { touchContent.style.right = `${postion + posX}px`; } if (direction === 'right') { const ContposX = posX > contentWidth ? contentWidth : posX; touchContent.style.left = `${distance - ContposX}px`; } setTimeout(() => { self.setState({ oldPosX: posX, }); }, 30); } swipingRight(e, posX) { const self = this, { touchContent } = this, { distance, postion, open, contentWidth, } = this.state, { direction } = this.props; if ((direction === 'right' && !open) || (direction === 'left' && open) || direction === 'bottom' || direction === 'up') { return false; } touchContent.style.WebkitTransition = 'none'; // 弹层跟随坐标 if (direction === 'left') { const ContposX = posX > contentWidth ? contentWidth : posX; touchContent.style.right = `${distance - ContposX}px`; } if (direction === 'right') { touchContent.style.left = `${postion + posX}px`; } setTimeout(() => { self.setState({ oldPosX: posX, }); }, 30); } swipingUp(e, posY) { const self = this, { touchContent, touchScroll, touchMain } = this, touchScrollTop = ReactDOM.findDOMNode(touchScroll).scrollTop, touchScrollHeight = ReactDOM.findDOMNode(touchScroll).clientHeight, touchMainHeight = ReactDOM.findDOMNode(touchMain).clientHeight, { distance, postion, open, contentHeight, } = this.state, { direction } = this.props; if (touchScrollTop + touchScrollHeight < touchMainHeight && direction !== 'bottom') { return; } if ((direction === 'bottom' && open) || (direction === 'top' && !open) || direction === 'left' || direction === 'right') { return; } // 阻止window窗体滚动 e.preventDefault && e.preventDefault(); touchContent.style.WebkitTransition = 'none'; // this.refs.touchScroll.style.overflow = "hidden" if (direction === 'bottom') { const ContposY = posY > contentHeight ? contentHeight : posY; touchContent.style.top = `${distance - ContposY}px`; } if (direction === 'top') { touchContent.style.bottom = `${postion + posY}px`; } setTimeout(() => { self.setState({ oldPosY: posY, }); }, 30); } initSetContentStyle(propsData) { const { touchContent } = this, { height, width, direction, align, } = propsData, windowW = document.documentElement ? document.documentElement.clientWidth : document.body.clientWidth, windowH = document.documentElement ? document.documentElement.clientHeight : document.body.clientHeight, mydistance = direction === 'bottom' || direction === 'top' ? windowH : windowW; let contentH = 0, conentW = 0; // 设置容器高度 if (height.indexOf('px') !== -1) { contentH = Number(height.split('px')[0]); } else { contentH = windowH; } // 设置容器宽度 if (width.indexOf('px') !== -1) { conentW = Number(width.split('px')[0]); } else { conentW = windowW; } this.setState({ distance: mydistance, // 模块高度 postion: direction === 'bottom' || direction === 'top' ? windowH - contentH : windowW - conentW, // 距离顶点位置 open: false, // 是否弹层已展开 contentHeight: contentH, contentWidth: conentW, oldPosY: 0, oldPosX: 0, }); let alignCssText = ''; if (direction === 'bottom' || direction === 'top') { switch (align) { case 0: alignCssText = 'transform:translate(-50%,0);-webkit-transform:translate(-50%,0);left:50%;'; break; case 1: alignCssText = 'left:0;'; break; case 2: alignCssText = 'right:0;'; break; default: alignCssText = ''; break; } } if (direction === 'left' || direction === 'right') { switch (align) { case 0: alignCssText = 'transform:translate(0,-50%);-webkit-transform:translate(0,-50%);top:50%;'; break; case 1: alignCssText = 'top:0;'; break; case 2: alignCssText = 'bottom:0;'; break; default: alignCssText = ''; break; } } touchContent.style.cssText = `width:${conentW}px;height:${contentH}px;${alignCssText}`; // 设置内容容器样式 if (direction === 'bottom') { touchContent.style.top = `${mydistance}px`; } if (direction === 'top') { touchContent.style.bottom = `${mydistance}px`; } if (direction === 'left') { touchContent.style.right = `${mydistance}px`; } if (direction === 'right') { touchContent.style.left = `${mydistance}px`; } } swiped(e, posX, posY) { const { touchContent, touchScroll, touchMain } = this, touchScrollTop = ReactDOM.findDOMNode(touchScroll).scrollTop, touchScrollHeight = ReactDOM.findDOMNode(touchScroll).clientHeight, touchMainHeight = ReactDOM.findDOMNode(touchMain).clientHeight, { open, postion, distance, oldPosY, oldPosX, } = this.state, { direction, degree } = this.props, posYabs = posY, posXabs = Math.abs(posX); if (direction === 'bottom') { if (open) { // 关闭状态 if (posYabs < oldPosY && touchScrollTop <= 0) { this.setContState(distance, false); } else { this.setContState(postion, true); } // if(posYabs > oldPosY){ // this.setContState(postion,true) // } } else { // 展开状态 if (posYabs > oldPosY) { this.setContState(postion, true); } else { this.setContState(distance, false); } } } if (direction === 'top') { if (open) { // 关闭状态 if (posYabs > oldPosY && touchScrollTop + touchScrollHeight >= touchMainHeight) { this.setContState(distance, false); } else { this.setContState(postion, true); } // if(posYabs < oldPosY){ // this.setContState(postion,true) // } } else { // 展开状态 if (posYabs < oldPosY) { this.setContState(postion, true); } else { this.setContState(distance, false); } } } if (direction === 'left' || direction === 'right') { if (open) { // 关闭状态 if (posXabs >= oldPosX && posXabs >= degree) { this.setContState(distance, false); } else { this.setContState(postion, true); } } else { // 展开状态 if (posXabs >= oldPosX && posXabs >= degree) { this.setContState(postion, true); } else { this.setContState(distance, false); } } } } showEven() { this._show(); } _show() { const { postion } = this.state; this.setContState(postion, true); } hideEven() { this._hide(); } _hide() { const { distance } = this.state; this.setContState(distance, false); } render() { const { className, children, direction } = this.props, cls = classNames({ 'jimu-swipemove': true, 'jimu-bottom': direction === 'bottom', 'jimu-top': direction === 'top', 'jimu-left': direction === 'left', 'jimu-right': direction === 'right', [className]: className, }); return ( <Swipeable className={cls} onSwipingUp={this.swipingUp} onSwipingDown={this.swipingDown} onSwipingLeft={this.swipingLeft} onSwipingRight={this.swipingRight} onSwiped={this.swiped} > <div className="touch-content" ref={(n) => { this.touchContent = n; }}> <div className="touch-layout"> <span className="touch-icon" /> </div> <div className="touch-scroll" ref={(n) => { this.touchScroll = n; }}> <div className="touch-main" ref={(n) => { this.touchMain = n; }}> {children} </div> </div> </div> </Swipeable> ); } } export default SwipeMove;