Skip to content

Commit 0345587

Browse files
committed
fix(SwipeAction): 修复 SwipeAction 滑动卡顿的问题
1 parent c601ebf commit 0345587

File tree

6 files changed

+119
-204
lines changed

6 files changed

+119
-204
lines changed

packages/taro-ui/config/rollup.config.js

-11
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,6 @@ export default {
2929
file: resolveFile(Package.module),
3030
format: 'es',
3131
sourcemap: true
32-
},
33-
{
34-
file: resolveFile(Package.browser),
35-
format: 'umd',
36-
name: 'taro-ui',
37-
sourcemap: true,
38-
globals: {
39-
react: 'React',
40-
'@tarojs/components': 'components',
41-
'@tarojs/taro': 'Taro'
42-
}
4332
}
4433
],
4534
external: externalPackages,

packages/taro-ui/package.json

-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
"name": "taro-ui",
33
"version": "3.0.0-alpha.3",
44
"description": "UI KIT for Taro",
5-
"browser": "dist/index.umd.js",
65
"module": "dist/index.esm.js",
76
"main": "dist/index.js",
87
"source": "src/index.ts",

packages/taro-ui/src/components/swipe-action/index.tsx

+103-169
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,14 @@
11
import classNames from 'classnames'
2-
import _inRange from 'lodash/inRange'
3-
import _isEmpty from 'lodash/isEmpty'
42
import PropTypes, { InferProps } from 'prop-types'
53
import React from 'react'
6-
import { Text, View } from '@tarojs/components'
7-
import { CommonEvent, ITouchEvent } from '@tarojs/components/types/common'
4+
import { Text, View, MovableArea, MovableView } from '@tarojs/components'
5+
import { CommonEvent } from '@tarojs/components/types/common'
86
import {
97
AtSwipeActionProps,
108
AtSwipeActionState,
119
SwipeActionOption
1210
} from '../../../types/swipe-action'
13-
import {
14-
delayGetClientRect,
15-
delayGetScrollOffset,
16-
uuid
17-
} from '../../common/utils'
11+
import { uuid } from '../../common/utils'
1812
import AtSwipeActionOptions from './options/index'
1913

2014
export default class AtSwipeAction extends React.Component<
@@ -24,48 +18,22 @@ export default class AtSwipeAction extends React.Component<
2418
public static defaultProps: AtSwipeActionProps
2519
public static propTypes: InferProps<AtSwipeActionProps>
2620

27-
private endValue: number
28-
private startX: number
29-
private startY: number
3021
private maxOffsetSize: number
31-
private domInfo: any
32-
private isMoving: boolean
33-
private isTouching: boolean
22+
private moveX: number
23+
private eleWidth: number
3424

3525
public constructor(props: AtSwipeActionProps) {
3626
super(props)
37-
const { isOpened } = props
38-
this.endValue = 0
39-
this.startX = 0
40-
this.startY = 0
41-
this.maxOffsetSize = 0
42-
this.domInfo = {
43-
top: 0,
44-
bottom: 0,
45-
left: 0,
46-
right: 0
47-
}
48-
this.isMoving = false
49-
this.isTouching = false
27+
const { isOpened, maxDistance, areaWidth } = props
28+
this.maxOffsetSize = maxDistance
5029
this.state = {
5130
componentId: uuid(),
5231
offsetSize: 0,
53-
_isOpened: !!isOpened
32+
_isOpened: !!isOpened,
33+
needAnimation: false
5434
}
55-
}
56-
57-
private getDomInfo(): Promise<void> {
58-
return Promise.all([
59-
delayGetClientRect({
60-
delayTime: 0,
61-
selectorStr: `#swipeAction-${this.state.componentId}`
62-
}),
63-
delayGetScrollOffset({ delayTime: 0 })
64-
]).then(([rect, scrollOffset]) => {
65-
rect[0].top += scrollOffset[0].scrollTop
66-
rect[0].bottom += scrollOffset[0].scrollTop
67-
this.domInfo = rect[0]
68-
})
35+
this.moveX = 0
36+
this.eleWidth = areaWidth
6937
}
7038

7139
public UNSAFE_componentWillReceiveProps(nextProps: AtSwipeActionProps): void {
@@ -78,118 +46,40 @@ export default class AtSwipeAction extends React.Component<
7846
}
7947

8048
private _reset(isOpened: boolean): void {
81-
this.isMoving = false
82-
this.isTouching = false
83-
8449
if (isOpened) {
85-
this.endValue = -this.maxOffsetSize
8650
this.setState({
8751
_isOpened: true,
88-
offsetSize: -this.maxOffsetSize
52+
offsetSize: 0
8953
})
9054
} else {
91-
this.endValue = 0
92-
this.setState({
93-
offsetSize: 0,
94-
_isOpened: false
95-
})
55+
this.setState(
56+
{
57+
offsetSize: this.moveX
58+
},
59+
() => {
60+
this.setState({
61+
offsetSize: this.maxOffsetSize,
62+
_isOpened: false
63+
})
64+
}
65+
)
9666
}
9767
}
9868

99-
private computeTransform = (value: number): string | null =>
100-
// if (Taro.getEnv() === Taro.ENV_TYPE.ALIPAY) {
101-
// return !_isNil(value) ? `translate3d(${value}px,0,0)` : null
102-
// }
103-
value ? `translate3d(${value}px,0,0)` : null
104-
10569
private handleOpened = (event: CommonEvent): void => {
10670
const { onOpened } = this.props
107-
if (typeof onOpened === 'function' && this.state._isOpened) {
71+
if (typeof onOpened === 'function') {
10872
onOpened(event)
10973
}
11074
}
11175

11276
private handleClosed = (event: CommonEvent): void => {
11377
const { onClosed } = this.props
114-
if (typeof onClosed === 'function' && !this.state._isOpened) {
78+
if (typeof onClosed === 'function') {
11579
onClosed(event)
11680
}
11781
}
11882

119-
private handleTouchStart = (e: ITouchEvent): void => {
120-
const { clientX, clientY } = e.touches[0]
121-
122-
if (this.props.disabled) return
123-
124-
this.getDomInfo()
125-
126-
this.startX = clientX
127-
this.startY = clientY
128-
this.isTouching = true
129-
}
130-
131-
private handleTouchMove = (e: ITouchEvent): void => {
132-
if (_isEmpty(this.domInfo)) {
133-
return
134-
}
135-
136-
const { startX, startY } = this
137-
const { top, bottom, left, right } = this.domInfo
138-
const { clientX, clientY, pageX, pageY } = e.touches[0]
139-
140-
const x = Math.abs(clientX - startX)
141-
const y = Math.abs(clientY - startY)
142-
143-
const inDom = _inRange(pageX, left, right) && _inRange(pageY, top, bottom)
144-
145-
if (!this.isMoving && inDom) {
146-
this.isMoving =
147-
y === 0 ||
148-
x / y >= Number.parseFloat(Math.tan((45 * Math.PI) / 180).toFixed(2))
149-
}
150-
151-
if (this.isTouching && this.isMoving) {
152-
e.preventDefault()
153-
154-
const offsetSize = clientX - this.startX
155-
const isRight = offsetSize > 0
156-
157-
if (this.state.offsetSize === 0 && isRight) return
158-
159-
const value = this.endValue + offsetSize
160-
this.setState({
161-
offsetSize: value >= 0 ? 0 : value
162-
})
163-
}
164-
}
165-
166-
private handleTouchEnd = (event: ITouchEvent): void => {
167-
this.isTouching = false
168-
169-
const { offsetSize } = this.state
170-
171-
this.endValue = offsetSize
172-
173-
const breakpoint = this.maxOffsetSize / 2
174-
const absOffsetSize = Math.abs(offsetSize)
175-
176-
if (absOffsetSize > breakpoint) {
177-
this._reset(true)
178-
this.handleOpened(event)
179-
return
180-
}
181-
182-
this._reset(false) // TODO: Check behavior
183-
this.handleClosed(event)
184-
}
185-
186-
private handleDomInfo = ({ width }: { width: number }): void => {
187-
const { _isOpened } = this.state
188-
189-
this.maxOffsetSize = width
190-
this._reset(_isOpened)
191-
}
192-
19383
private handleClick = (
19484
item: SwipeActionOption,
19585
index: number,
@@ -206,51 +96,93 @@ export default class AtSwipeAction extends React.Component<
20696
}
20797
}
20898

99+
onTouchEnd = e => {
100+
if (this.moveX === 0) {
101+
this._reset(true)
102+
this.handleOpened(e)
103+
return
104+
}
105+
if (this.moveX === this.maxOffsetSize) {
106+
this._reset(false)
107+
this.handleClosed(e)
108+
return
109+
}
110+
if (this.state._isOpened && this.moveX > 0) {
111+
this._reset(false)
112+
this.handleClosed(e)
113+
return
114+
}
115+
if (this.maxOffsetSize - this.moveX < this.maxOffsetSize * 0.4) {
116+
this._reset(false)
117+
this.handleClosed(e)
118+
} else {
119+
this._reset(true)
120+
this.handleOpened(e)
121+
}
122+
}
123+
124+
onChange = e => {
125+
this.moveX = e.detail.x
126+
}
127+
209128
public render(): JSX.Element {
210-
const { offsetSize, componentId } = this.state
129+
const { componentId, offsetSize } = this.state
211130
const { options } = this.props
212131
const rootClass = classNames('at-swipe-action', this.props.className)
213-
const transform = this.computeTransform(offsetSize)
214-
const transformStyle: React.CSSProperties = transform ? { transform } : {}
215132

216133
return (
217134
<View
218135
id={`swipeAction-${componentId}`}
219136
className={rootClass}
220-
onTouchMove={this.handleTouchMove}
221-
onTouchEnd={this.handleTouchEnd}
222-
onTouchStart={this.handleTouchStart}
137+
style={{
138+
width: `${this.eleWidth}px`
139+
}}
223140
>
224-
<View
225-
className={classNames('at-swipe-action__content', {
226-
animtion: !this.isTouching
227-
})}
228-
style={transformStyle}
141+
<MovableArea
142+
className='at-swipe-action__area'
143+
style={{
144+
width: `${this.eleWidth + this.maxOffsetSize}px`,
145+
transform: `translate(-${this.maxOffsetSize}px, 0)`
146+
}}
229147
>
230-
{this.props.children}
231-
</View>
232-
233-
{Array.isArray(options) && options.length > 0 ? (
234-
<AtSwipeActionOptions
235-
options={options}
236-
componentId={componentId}
237-
onQueryedDom={this.handleDomInfo}
148+
<MovableView
149+
className='at-swipe-action__content'
150+
direction='horizontal'
151+
damping={50}
152+
x={offsetSize}
153+
onTouchEnd={this.onTouchEnd}
154+
onChange={this.onChange}
155+
style={{
156+
width: `${this.eleWidth}px`
157+
}}
238158
>
239-
{options.map((item, key) => (
240-
<View
241-
key={`${item.text}-${key}`}
242-
style={item.style}
243-
onClick={(e): void => this.handleClick(item, key, e)}
244-
className={classNames(
245-
'at-swipe-action__option',
246-
item.className
247-
)}
159+
{this.props.children}
160+
{Array.isArray(options) && options.length > 0 ? (
161+
<AtSwipeActionOptions
162+
options={options}
163+
componentId={componentId}
164+
customStyle={{
165+
transform: `translate(${this.maxOffsetSize}px, 0)`,
166+
opacity: 1
167+
}}
248168
>
249-
<Text className='option__text'>{item.text}</Text>
250-
</View>
251-
))}
252-
</AtSwipeActionOptions>
253-
) : null}
169+
{options.map((item, key) => (
170+
<View
171+
key={`${item.text}-${key}`}
172+
style={item.style}
173+
onClick={(e): void => this.handleClick(item, key, e)}
174+
className={classNames(
175+
'at-swipe-action__option',
176+
item.className
177+
)}
178+
>
179+
<Text className='option__text'>{item.text}</Text>
180+
</View>
181+
))}
182+
</AtSwipeActionOptions>
183+
) : null}
184+
</MovableView>
185+
</MovableArea>
254186
</View>
255187
)
256188
}
@@ -260,7 +192,9 @@ AtSwipeAction.defaultProps = {
260192
options: [],
261193
isOpened: false,
262194
disabled: false,
263-
autoClose: false
195+
autoClose: false,
196+
maxDistance: 0,
197+
areaWidth: 0
264198
}
265199

266200
AtSwipeAction.propTypes = {

0 commit comments

Comments
 (0)