From 6d3e0b006c5908160eab8642844fc5f3dcb54bc0 Mon Sep 17 00:00:00 2001 From: luckyadam <weitaozsh@gmail.com> Date: Thu, 17 Dec 2020 16:57:15 +0800 Subject: [PATCH] =?UTF-8?q?fix(SwipeAction):=20=E4=BF=AE=E5=A4=8D=20SwipeA?= =?UTF-8?q?ction=20=E6=BB=91=E5=8A=A8=E5=8D=A1=E9=A1=BF=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-ui/config/rollup.config.js | 11 - packages/taro-ui/package.json | 1 - .../src/components/swipe-action/index.tsx | 286 ++++++++---------- .../src/style/components/swipe-action.scss | 7 + packages/taro-ui/types/swipe-action.d.ts | 1 + 5 files changed, 136 insertions(+), 170 deletions(-) diff --git a/packages/taro-ui/config/rollup.config.js b/packages/taro-ui/config/rollup.config.js index a1ba6b589..237f2940a 100644 --- a/packages/taro-ui/config/rollup.config.js +++ b/packages/taro-ui/config/rollup.config.js @@ -29,17 +29,6 @@ export default { file: resolveFile(Package.module), format: 'es', sourcemap: true - }, - { - file: resolveFile(Package.browser), - format: 'umd', - name: 'taro-ui', - sourcemap: true, - globals: { - react: 'React', - '@tarojs/components': 'components', - '@tarojs/taro': 'Taro' - } } ], external: externalPackages, diff --git a/packages/taro-ui/package.json b/packages/taro-ui/package.json index f61c20b43..4467fdb9b 100644 --- a/packages/taro-ui/package.json +++ b/packages/taro-ui/package.json @@ -2,7 +2,6 @@ "name": "taro-ui", "version": "3.0.0-alpha.3", "description": "UI KIT for Taro", - "browser": "dist/index.umd.js", "module": "dist/index.esm.js", "main": "dist/index.js", "source": "src/index.ts", diff --git a/packages/taro-ui/src/components/swipe-action/index.tsx b/packages/taro-ui/src/components/swipe-action/index.tsx index d68c13a48..873f3c65a 100644 --- a/packages/taro-ui/src/components/swipe-action/index.tsx +++ b/packages/taro-ui/src/components/swipe-action/index.tsx @@ -1,20 +1,14 @@ import classNames from 'classnames' -import _inRange from 'lodash/inRange' -import _isEmpty from 'lodash/isEmpty' import PropTypes, { InferProps } from 'prop-types' import React from 'react' -import { Text, View } from '@tarojs/components' -import { CommonEvent, ITouchEvent } from '@tarojs/components/types/common' +import { Text, View, MovableArea, MovableView } from '@tarojs/components' +import { CommonEvent } from '@tarojs/components/types/common' import { AtSwipeActionProps, AtSwipeActionState, SwipeActionOption } from '../../../types/swipe-action' -import { - delayGetClientRect, - delayGetScrollOffset, - uuid -} from '../../common/utils' +import { delayQuerySelector, uuid } from '../../common/utils' import AtSwipeActionOptions from './options/index' export default class AtSwipeAction extends React.Component< @@ -24,48 +18,22 @@ export default class AtSwipeAction extends React.Component< public static defaultProps: AtSwipeActionProps public static propTypes: InferProps<AtSwipeActionProps> - private endValue: number - private startX: number - private startY: number private maxOffsetSize: number - private domInfo: any - private isMoving: boolean - private isTouching: boolean + private moveX: number + private eleWidth: number public constructor(props: AtSwipeActionProps) { super(props) const { isOpened } = props - this.endValue = 0 - this.startX = 0 - this.startY = 0 this.maxOffsetSize = 0 - this.domInfo = { - top: 0, - bottom: 0, - left: 0, - right: 0 - } - this.isMoving = false - this.isTouching = false this.state = { componentId: uuid(), offsetSize: 0, - _isOpened: !!isOpened + _isOpened: !!isOpened, + needAnimation: false } - } - - private getDomInfo(): Promise<void> { - return Promise.all([ - delayGetClientRect({ - delayTime: 0, - selectorStr: `#swipeAction-${this.state.componentId}` - }), - delayGetScrollOffset({ delayTime: 0 }) - ]).then(([rect, scrollOffset]) => { - rect[0].top += scrollOffset[0].scrollTop - rect[0].bottom += scrollOffset[0].scrollTop - this.domInfo = rect[0] - }) + this.moveX = 0 + this.eleWidth = 0 } public UNSAFE_componentWillReceiveProps(nextProps: AtSwipeActionProps): void { @@ -77,31 +45,49 @@ export default class AtSwipeAction extends React.Component< } } - private _reset(isOpened: boolean): void { - this.isMoving = false - this.isTouching = false + public componentDidMount(): void { + if (this.eleWidth === 0) { + delayQuerySelector(`#swipeAction-${this.state.componentId}`, 0).then( + res => { + if (res[0]) { + this.eleWidth = res[0].width + } + } + ) + } + } + public componentDidUpdate(): void { + delayQuerySelector(`#swipeAction-${this.state.componentId}`, 0).then( + res => { + if (res[0]) { + this.eleWidth = res[0].width + } + } + ) + } + + private _reset(isOpened: boolean): void { if (isOpened) { - this.endValue = -this.maxOffsetSize this.setState({ _isOpened: true, - offsetSize: -this.maxOffsetSize + offsetSize: 0 }) } else { - this.endValue = 0 - this.setState({ - offsetSize: 0, - _isOpened: false - }) + this.setState( + { + offsetSize: this.moveX + }, + () => { + this.setState({ + offsetSize: this.maxOffsetSize, + _isOpened: false + }) + } + ) } } - private computeTransform = (value: number): string | null => - // if (Taro.getEnv() === Taro.ENV_TYPE.ALIPAY) { - // return !_isNil(value) ? `translate3d(${value}px,0,0)` : null - // } - value ? `translate3d(${value}px,0,0)` : null - private handleOpened = (event: CommonEvent): void => { const { onOpened } = this.props if (typeof onOpened === 'function' && this.state._isOpened) { @@ -116,78 +102,16 @@ export default class AtSwipeAction extends React.Component< } } - private handleTouchStart = (e: ITouchEvent): void => { - const { clientX, clientY } = e.touches[0] - - if (this.props.disabled) return - - this.getDomInfo() - - this.startX = clientX - this.startY = clientY - this.isTouching = true - } - - private handleTouchMove = (e: ITouchEvent): void => { - if (_isEmpty(this.domInfo)) { - return - } - - const { startX, startY } = this - const { top, bottom, left, right } = this.domInfo - const { clientX, clientY, pageX, pageY } = e.touches[0] - - const x = Math.abs(clientX - startX) - const y = Math.abs(clientY - startY) - - const inDom = _inRange(pageX, left, right) && _inRange(pageY, top, bottom) - - if (!this.isMoving && inDom) { - this.isMoving = - y === 0 || - x / y >= Number.parseFloat(Math.tan((45 * Math.PI) / 180).toFixed(2)) - } - - if (this.isTouching && this.isMoving) { - e.preventDefault() - - const offsetSize = clientX - this.startX - const isRight = offsetSize > 0 - - if (this.state.offsetSize === 0 && isRight) return - - const value = this.endValue + offsetSize - this.setState({ - offsetSize: value >= 0 ? 0 : value - }) - } - } - - private handleTouchEnd = (event: ITouchEvent): void => { - this.isTouching = false - - const { offsetSize } = this.state - - this.endValue = offsetSize - - const breakpoint = this.maxOffsetSize / 2 - const absOffsetSize = Math.abs(offsetSize) - - if (absOffsetSize > breakpoint) { - this._reset(true) - this.handleOpened(event) - return - } - - this._reset(false) // TODO: Check behavior - this.handleClosed(event) - } - private handleDomInfo = ({ width }: { width: number }): void => { const { _isOpened } = this.state this.maxOffsetSize = width this._reset(_isOpened) + setTimeout(() => { + this.setState({ + needAnimation: true + }) + }, 0) } private handleClick = ( @@ -206,51 +130,97 @@ export default class AtSwipeAction extends React.Component< } } + onTouchEnd = e => { + if (this.moveX === 0) { + this._reset(true) + this.handleOpened(e) + return + } + if (this.moveX === this.maxOffsetSize) { + this._reset(false) + this.handleClosed(e) + return + } + if (this.state._isOpened && this.moveX > 0) { + this._reset(false) + this.handleClosed(e) + return + } + if (this.maxOffsetSize - this.moveX < this.maxOffsetSize * 0.4) { + this._reset(false) + this.handleClosed(e) + } else { + this._reset(true) + this.handleOpened(e) + } + } + + onChange = e => { + this.moveX = e.detail.x + } + public render(): JSX.Element { - const { offsetSize, componentId } = this.state + const { componentId, offsetSize, needAnimation } = this.state const { options } = this.props const rootClass = classNames('at-swipe-action', this.props.className) - const transform = this.computeTransform(offsetSize) - const transformStyle: React.CSSProperties = transform ? { transform } : {} return ( <View id={`swipeAction-${componentId}`} className={rootClass} - onTouchMove={this.handleTouchMove} - onTouchEnd={this.handleTouchEnd} - onTouchStart={this.handleTouchStart} + style={{ + width: this.eleWidth === 0 ? '100%' : `${this.eleWidth}px` + }} > - <View - className={classNames('at-swipe-action__content', { - animtion: !this.isTouching - })} - style={transformStyle} + <MovableArea + className='at-swipe-action__area' + style={{ + width: + this.eleWidth === 0 + ? '100%' + : `${this.eleWidth + this.maxOffsetSize}px`, + transform: + this.eleWidth === 0 + ? `translate(0, 0)` + : `translate(-${this.maxOffsetSize}px, 0)` + }} > - {this.props.children} - </View> - - {Array.isArray(options) && options.length > 0 ? ( - <AtSwipeActionOptions - options={options} - componentId={componentId} - onQueryedDom={this.handleDomInfo} + <MovableView + className='at-swipe-action__content' + direction='horizontal' + damping={50} + x={offsetSize} + onTouchEnd={this.onTouchEnd} + onChange={this.onChange} + animation={needAnimation} + style={{ + width: this.eleWidth === 0 ? '100%' : `${this.eleWidth}px` + }} > - {options.map((item, key) => ( - <View - key={`${item.text}-${key}`} - style={item.style} - onClick={(e): void => this.handleClick(item, key, e)} - className={classNames( - 'at-swipe-action__option', - item.className - )} - > - <Text className='option__text'>{item.text}</Text> - </View> - ))} - </AtSwipeActionOptions> - ) : null} + {this.props.children} + </MovableView> + {Array.isArray(options) && options.length > 0 ? ( + <AtSwipeActionOptions + options={options} + componentId={componentId} + onQueryedDom={this.handleDomInfo} + > + {options.map((item, key) => ( + <View + key={`${item.text}-${key}`} + style={item.style} + onClick={(e): void => this.handleClick(item, key, e)} + className={classNames( + 'at-swipe-action__option', + item.className + )} + > + <Text className='option__text'>{item.text}</Text> + </View> + ))} + </AtSwipeActionOptions> + ) : null} + </MovableArea> </View> ) } diff --git a/packages/taro-ui/src/style/components/swipe-action.scss b/packages/taro-ui/src/style/components/swipe-action.scss index 827ba2485..db83c9a8a 100644 --- a/packages/taro-ui/src/style/components/swipe-action.scss +++ b/packages/taro-ui/src/style/components/swipe-action.scss @@ -4,12 +4,19 @@ .at-swipe-action { position: relative; overflow: hidden; + width: 100%; + + &__area { + height: auto; + } /* elements */ &__content { position: relative; font-size: $font-size-lg; background-color: $at-swipe-action-bg-color; + display: flex; + height: 100%; z-index: 2; &.animtion { diff --git a/packages/taro-ui/types/swipe-action.d.ts b/packages/taro-ui/types/swipe-action.d.ts index d8a3f2150..fc2d85e5c 100644 --- a/packages/taro-ui/types/swipe-action.d.ts +++ b/packages/taro-ui/types/swipe-action.d.ts @@ -59,6 +59,7 @@ export interface AtSwipeActionState { componentId: string offsetSize: number _isOpened: boolean + needAnimation: boolean } export interface AtSwipeActionOptionsProps extends AtComponent {