1
1
import classNames from 'classnames'
2
- import _inRange from 'lodash/inRange'
3
- import _isEmpty from 'lodash/isEmpty'
4
2
import PropTypes , { InferProps } from 'prop-types'
5
3
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'
8
6
import {
9
7
AtSwipeActionProps ,
10
8
AtSwipeActionState ,
11
9
SwipeActionOption
12
10
} from '../../../types/swipe-action'
13
- import {
14
- delayGetClientRect ,
15
- delayGetScrollOffset ,
16
- uuid
17
- } from '../../common/utils'
11
+ import { delayQuerySelector , uuid } from '../../common/utils'
18
12
import AtSwipeActionOptions from './options/index'
19
13
20
14
export default class AtSwipeAction extends React . Component <
@@ -24,48 +18,22 @@ export default class AtSwipeAction extends React.Component<
24
18
public static defaultProps : AtSwipeActionProps
25
19
public static propTypes : InferProps < AtSwipeActionProps >
26
20
27
- private endValue : number
28
- private startX : number
29
- private startY : number
30
21
private maxOffsetSize : number
31
- private domInfo : any
32
- private isMoving : boolean
33
- private isTouching : boolean
22
+ private moveX : number
23
+ private eleWidth : number
34
24
35
25
public constructor ( props : AtSwipeActionProps ) {
36
26
super ( props )
37
27
const { isOpened } = props
38
- this . endValue = 0
39
- this . startX = 0
40
- this . startY = 0
41
28
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
50
29
this . state = {
51
30
componentId : uuid ( ) ,
52
31
offsetSize : 0 ,
53
- _isOpened : ! ! isOpened
32
+ _isOpened : ! ! isOpened ,
33
+ needAnimation : false
54
34
}
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 = 0
69
37
}
70
38
71
39
public UNSAFE_componentWillReceiveProps ( nextProps : AtSwipeActionProps ) : void {
@@ -77,31 +45,49 @@ export default class AtSwipeAction extends React.Component<
77
45
}
78
46
}
79
47
80
- private _reset ( isOpened : boolean ) : void {
81
- this . isMoving = false
82
- this . isTouching = false
48
+ public componentDidMount ( ) : void {
49
+ if ( this . eleWidth === 0 ) {
50
+ delayQuerySelector ( `#swipeAction-${ this . state . componentId } ` , 0 ) . then (
51
+ res => {
52
+ if ( res [ 0 ] ) {
53
+ this . eleWidth = res [ 0 ] . width
54
+ }
55
+ }
56
+ )
57
+ }
58
+ }
83
59
60
+ public componentDidUpdate ( ) : void {
61
+ delayQuerySelector ( `#swipeAction-${ this . state . componentId } ` , 0 ) . then (
62
+ res => {
63
+ if ( res [ 0 ] ) {
64
+ this . eleWidth = res [ 0 ] . width
65
+ }
66
+ }
67
+ )
68
+ }
69
+
70
+ private _reset ( isOpened : boolean ) : void {
84
71
if ( isOpened ) {
85
- this . endValue = - this . maxOffsetSize
86
72
this . setState ( {
87
73
_isOpened : true ,
88
- offsetSize : - this . maxOffsetSize
74
+ offsetSize : 0
89
75
} )
90
76
} else {
91
- this . endValue = 0
92
- this . setState ( {
93
- offsetSize : 0 ,
94
- _isOpened : false
95
- } )
77
+ this . setState (
78
+ {
79
+ offsetSize : this . moveX
80
+ } ,
81
+ ( ) => {
82
+ this . setState ( {
83
+ offsetSize : this . maxOffsetSize ,
84
+ _isOpened : false
85
+ } )
86
+ }
87
+ )
96
88
}
97
89
}
98
90
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
-
105
91
private handleOpened = ( event : CommonEvent ) : void => {
106
92
const { onOpened } = this . props
107
93
if ( typeof onOpened === 'function' && this . state . _isOpened ) {
@@ -116,78 +102,16 @@ export default class AtSwipeAction extends React.Component<
116
102
}
117
103
}
118
104
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
105
private handleDomInfo = ( { width } : { width : number } ) : void => {
187
106
const { _isOpened } = this . state
188
107
189
108
this . maxOffsetSize = width
190
109
this . _reset ( _isOpened )
110
+ setTimeout ( ( ) => {
111
+ this . setState ( {
112
+ needAnimation : true
113
+ } )
114
+ } , 0 )
191
115
}
192
116
193
117
private handleClick = (
@@ -206,51 +130,97 @@ export default class AtSwipeAction extends React.Component<
206
130
}
207
131
}
208
132
133
+ onTouchEnd = e => {
134
+ if ( this . moveX === 0 ) {
135
+ this . _reset ( true )
136
+ this . handleOpened ( e )
137
+ return
138
+ }
139
+ if ( this . moveX === this . maxOffsetSize ) {
140
+ this . _reset ( false )
141
+ this . handleClosed ( e )
142
+ return
143
+ }
144
+ if ( this . state . _isOpened && this . moveX > 0 ) {
145
+ this . _reset ( false )
146
+ this . handleClosed ( e )
147
+ return
148
+ }
149
+ if ( this . maxOffsetSize - this . moveX < this . maxOffsetSize * 0.4 ) {
150
+ this . _reset ( false )
151
+ this . handleClosed ( e )
152
+ } else {
153
+ this . _reset ( true )
154
+ this . handleOpened ( e )
155
+ }
156
+ }
157
+
158
+ onChange = e => {
159
+ this . moveX = e . detail . x
160
+ }
161
+
209
162
public render ( ) : JSX . Element {
210
- const { offsetSize, componentId } = this . state
163
+ const { componentId , offsetSize, needAnimation } = this . state
211
164
const { options } = this . props
212
165
const rootClass = classNames ( 'at-swipe-action' , this . props . className )
213
- const transform = this . computeTransform ( offsetSize )
214
- const transformStyle : React . CSSProperties = transform ? { transform } : { }
215
166
216
167
return (
217
168
< View
218
169
id = { `swipeAction-${ componentId } ` }
219
170
className = { rootClass }
220
- onTouchMove = { this . handleTouchMove }
221
- onTouchEnd = { this . handleTouchEnd }
222
- onTouchStart = { this . handleTouchStart }
171
+ style = { {
172
+ width : this . eleWidth === 0 ? '100%' : ` $ {this . eleWidth } px`
173
+ } }
223
174
>
224
- < View
225
- className = { classNames ( 'at-swipe-action__content' , {
226
- animtion : ! this . isTouching
227
- } ) }
228
- style = { transformStyle }
175
+ < MovableArea
176
+ className = 'at-swipe-action__area'
177
+ style = { {
178
+ width :
179
+ this . eleWidth === 0
180
+ ? '100%'
181
+ : `${ this . eleWidth + this . maxOffsetSize } px` ,
182
+ transform :
183
+ this . eleWidth === 0
184
+ ? `translate(0, 0)`
185
+ : `translate(-${ this . maxOffsetSize } px, 0)`
186
+ } }
229
187
>
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 }
188
+ < MovableView
189
+ className = 'at-swipe-action__content'
190
+ direction = 'horizontal'
191
+ damping = { 50 }
192
+ x = { offsetSize }
193
+ onTouchEnd = { this . onTouchEnd }
194
+ onChange = { this . onChange }
195
+ animation = { needAnimation }
196
+ style = { {
197
+ width : this . eleWidth === 0 ? '100%' : `${ this . eleWidth } px`
198
+ } }
238
199
>
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
- ) }
248
- >
249
- < Text className = 'option__text' > { item . text } </ Text >
250
- </ View >
251
- ) ) }
252
- </ AtSwipeActionOptions >
253
- ) : null }
200
+ { this . props . children }
201
+ </ MovableView >
202
+ { Array . isArray ( options ) && options . length > 0 ? (
203
+ < AtSwipeActionOptions
204
+ options = { options }
205
+ componentId = { componentId }
206
+ onQueryedDom = { this . handleDomInfo }
207
+ >
208
+ { options . map ( ( item , key ) => (
209
+ < View
210
+ key = { `${ item . text } -${ key } ` }
211
+ style = { item . style }
212
+ onClick = { ( e ) : void => this . handleClick ( item , key , e ) }
213
+ className = { classNames (
214
+ 'at-swipe-action__option' ,
215
+ item . className
216
+ ) }
217
+ >
218
+ < Text className = 'option__text' > { item . text } </ Text >
219
+ </ View >
220
+ ) ) }
221
+ </ AtSwipeActionOptions >
222
+ ) : null }
223
+ </ MovableArea >
254
224
</ View >
255
225
)
256
226
}
0 commit comments