@mpxjs/webpack-plugin 2.10.17-unocss.1 → 2.10.18-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.js +49 -36
- package/lib/platform/style/wx/index.js +0 -2
- package/lib/platform/template/wx/component-config/camera.js +12 -0
- package/lib/platform/template/wx/component-config/unsupported.js +1 -1
- package/lib/react/processStyles.js +8 -39
- package/lib/react/style-helper.js +5 -16
- package/lib/resolver/ExtendComponentsPlugin.js +60 -0
- package/lib/runtime/components/ali/mpx-section-list.mpx +566 -0
- package/lib/runtime/components/ali/mpx-sticky-header.mpx +212 -0
- package/lib/runtime/components/ali/mpx-sticky-section.mpx +17 -0
- package/lib/runtime/components/react/dist/animationHooks/useAnimationAPIHooks.js +0 -1
- package/lib/runtime/components/react/dist/mpx-async-suspense.jsx +2 -1
- package/lib/runtime/components/react/dist/mpx-input.jsx +10 -3
- package/lib/runtime/components/react/dist/mpx-keyboard-avoiding-view.jsx +13 -2
- package/lib/runtime/components/react/dist/mpx-swiper.jsx +60 -40
- package/lib/runtime/components/react/dist/utils.jsx +8 -4
- package/lib/runtime/components/react/mpx-async-suspense.tsx +2 -1
- package/lib/runtime/components/react/mpx-camera.tsx +327 -0
- package/lib/runtime/components/react/mpx-input.tsx +11 -2
- package/lib/runtime/components/react/mpx-keyboard-avoiding-view.tsx +13 -2
- package/lib/runtime/components/react/mpx-section-list.tsx +439 -0
- package/lib/runtime/components/react/mpx-swiper.tsx +113 -66
- package/lib/runtime/components/react/mpx-web-view.tsx +1 -1
- package/lib/runtime/components/react/tsconfig.json +1 -1
- package/lib/runtime/components/react/utils.tsx +8 -4
- package/lib/runtime/components/web/mpx-scroll-view.vue +5 -2
- package/lib/runtime/components/web/mpx-section-list.vue +551 -0
- package/lib/runtime/components/wx/mpx-section-list-default/list-footer.mpx +26 -0
- package/lib/runtime/components/wx/mpx-section-list-default/list-header.mpx +26 -0
- package/lib/runtime/components/wx/mpx-section-list-default/list-item.mpx +26 -0
- package/lib/runtime/components/wx/mpx-section-list-default/section-header.mpx +26 -0
- package/lib/runtime/components/wx/mpx-section-list.mpx +209 -0
- package/lib/runtime/components/wx/mpx-sticky-header.mpx +40 -0
- package/lib/runtime/components/wx/mpx-sticky-section.mpx +31 -0
- package/lib/template-compiler/compiler.js +7 -3
- package/lib/utils/const.js +29 -0
- package/lib/utils/dom-tag-config.js +1 -1
- package/lib/wxss/loader.js +4 -1
- package/lib/wxss/utils.js +7 -2
- package/package.json +3 -3
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
import React, { createElement, forwardRef, useRef, useCallback, useContext, useState, useEffect } from 'react'
|
|
2
|
+
import { useTransformStyle, useLayout, extendObject } from './utils'
|
|
3
|
+
import useInnerProps, { getCustomEvent } from './getInnerListeners'
|
|
4
|
+
import { noop } from '@mpxjs/utils'
|
|
5
|
+
import { RouteContext } from './context'
|
|
6
|
+
|
|
7
|
+
const qualityValue = {
|
|
8
|
+
high: 90,
|
|
9
|
+
normal: 75,
|
|
10
|
+
low: 50,
|
|
11
|
+
original: 100
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface CameraProps {
|
|
15
|
+
mode?: 'normal' | 'scanCode'
|
|
16
|
+
resolution?: 'low' | 'medium' | 'high'
|
|
17
|
+
devicePosition?: 'front' | 'back'
|
|
18
|
+
flash?: 'auto' | 'on' | 'off'
|
|
19
|
+
frameSize?: 'small' | 'medium' | 'large'
|
|
20
|
+
style?: Record<string, any>
|
|
21
|
+
bindstop?: () => void
|
|
22
|
+
binderror?: (error: { message: string }) => void
|
|
23
|
+
bindinitdone?: (result: { type: string, data: string }) => void
|
|
24
|
+
bindscancode?: (result: { type: string, data: string }) => void
|
|
25
|
+
'parent-font-size'?: number
|
|
26
|
+
'parent-width'?: number
|
|
27
|
+
'parent-height'?: number
|
|
28
|
+
'enable-var'?: boolean
|
|
29
|
+
'external-var-context'?: any
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
interface TakePhotoOptions {
|
|
33
|
+
quality?: 'high' | 'normal' | 'low' | 'original'
|
|
34
|
+
success?: (result: { errMsg: string, tempImagePath: string }) => void
|
|
35
|
+
fail?: (result: { errMsg: string }) => void
|
|
36
|
+
complete?: (result: { errMsg: string, tempImagePath?: string }) => void
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
interface RecordOptions {
|
|
40
|
+
timeout?: number
|
|
41
|
+
success?: (result: { errMsg: string }) => void
|
|
42
|
+
fail?: (result: { errMsg: string, error?: any }) => void
|
|
43
|
+
complete?: (result: { errMsg: string }) => void
|
|
44
|
+
timeoutCallback?: (result: { errMsg: string, error?: any }) => void
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface StopRecordOptions {
|
|
48
|
+
success?: (result: { errMsg: string, tempVideoPath: string, duration: number }) => void
|
|
49
|
+
fail?: (result: { errMsg: string }) => void
|
|
50
|
+
complete?: (result: { errMsg: string, tempVideoPath?: string, duration?: number }) => void
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
interface CameraRef {
|
|
54
|
+
setZoom: (zoom: number) => void
|
|
55
|
+
takePhoto: (options?: TakePhotoOptions) => void
|
|
56
|
+
startRecord: (options?: RecordOptions) => void
|
|
57
|
+
stopRecord: (options?: StopRecordOptions) => void
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
type HandlerRef<T, P> = {
|
|
61
|
+
current: T | null
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
let RecordRes: any = null
|
|
65
|
+
|
|
66
|
+
const _camera = forwardRef<HandlerRef<any, CameraProps>, CameraProps>((props: CameraProps, ref): JSX.Element | null => {
|
|
67
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
68
|
+
const { Camera, useCameraDevice, useCodeScanner, useCameraFormat } = require('react-native-vision-camera')
|
|
69
|
+
const cameraRef = useRef<any>(null)
|
|
70
|
+
const {
|
|
71
|
+
mode = 'normal',
|
|
72
|
+
resolution = 'medium',
|
|
73
|
+
devicePosition = 'back',
|
|
74
|
+
flash = 'auto',
|
|
75
|
+
frameSize = 'medium',
|
|
76
|
+
bindinitdone,
|
|
77
|
+
bindstop,
|
|
78
|
+
bindscancode,
|
|
79
|
+
'parent-font-size': parentFontSize,
|
|
80
|
+
'parent-width': parentWidth,
|
|
81
|
+
'parent-height': parentHeight,
|
|
82
|
+
'enable-var': enableVar,
|
|
83
|
+
'external-var-context': externalVarContext,
|
|
84
|
+
style = {}
|
|
85
|
+
} = props
|
|
86
|
+
const styleObj = extendObject(
|
|
87
|
+
{},
|
|
88
|
+
style
|
|
89
|
+
)
|
|
90
|
+
const {
|
|
91
|
+
normalStyle,
|
|
92
|
+
hasSelfPercent,
|
|
93
|
+
setWidth,
|
|
94
|
+
setHeight
|
|
95
|
+
} = useTransformStyle(styleObj, {
|
|
96
|
+
enableVar,
|
|
97
|
+
externalVarContext,
|
|
98
|
+
parentFontSize,
|
|
99
|
+
parentWidth,
|
|
100
|
+
parentHeight
|
|
101
|
+
})
|
|
102
|
+
const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: cameraRef })
|
|
103
|
+
const isPhoto = mode === 'normal'
|
|
104
|
+
const device = useCameraDevice(devicePosition || 'back')
|
|
105
|
+
const { navigation } = useContext(RouteContext) || {}
|
|
106
|
+
const [zoomValue, setZoomValue] = useState<number>(1)
|
|
107
|
+
const [hasPermission, setHasPermission] = useState<boolean | null>(null)
|
|
108
|
+
const hasCamera = useRef(false)
|
|
109
|
+
|
|
110
|
+
// 先定义常量,避免在条件判断后使用
|
|
111
|
+
const maxZoom = device?.maxZoom || 1
|
|
112
|
+
const RESOLUTION_MAPPING: Record<string, { width: number, height: number }> = {
|
|
113
|
+
low: { width: 640, height: 480 },
|
|
114
|
+
medium: { width: 1280, height: 720 },
|
|
115
|
+
high: { width: 1920, height: 1080 }
|
|
116
|
+
}
|
|
117
|
+
const FRAME_SIZE_MAPPING: Record<string, { width: number, height: number }> = {
|
|
118
|
+
small: { width: 480, height: 360 },
|
|
119
|
+
medium: { width: 720, height: 540 },
|
|
120
|
+
large: { width: 1080, height: 810 }
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const format = useCameraFormat(device, [
|
|
124
|
+
{
|
|
125
|
+
photoResolution: RESOLUTION_MAPPING[resolution],
|
|
126
|
+
videoResolution: FRAME_SIZE_MAPPING[frameSize] || RESOLUTION_MAPPING[resolution]
|
|
127
|
+
}
|
|
128
|
+
])
|
|
129
|
+
|
|
130
|
+
const codeScanner = useCodeScanner({
|
|
131
|
+
codeTypes: ['qr', 'ean-13'],
|
|
132
|
+
onCodeScanned: (codes: any[]) => {
|
|
133
|
+
const result = codes.map(code => code.value).join(',')
|
|
134
|
+
bindscancode && bindscancode(getCustomEvent('scancode', {}, {
|
|
135
|
+
detail: {
|
|
136
|
+
result: codes.map(code => code.value).join(',')
|
|
137
|
+
}
|
|
138
|
+
}))
|
|
139
|
+
}
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
const onInitialized = useCallback(() => {
|
|
143
|
+
bindinitdone && bindinitdone(getCustomEvent('initdone', {}, {
|
|
144
|
+
detail: {
|
|
145
|
+
maxZoom
|
|
146
|
+
}
|
|
147
|
+
}))
|
|
148
|
+
}, [bindinitdone, maxZoom])
|
|
149
|
+
|
|
150
|
+
const onStopped = useCallback(() => {
|
|
151
|
+
bindstop && bindstop()
|
|
152
|
+
}, [bindstop])
|
|
153
|
+
|
|
154
|
+
const camera: CameraRef = {
|
|
155
|
+
setZoom: (zoom: number) => {
|
|
156
|
+
setZoomValue(zoom)
|
|
157
|
+
},
|
|
158
|
+
takePhoto: (options: TakePhotoOptions = {}) => {
|
|
159
|
+
const { success = noop, fail = noop, complete = noop } = options
|
|
160
|
+
cameraRef.current?.takePhoto?.({
|
|
161
|
+
flash,
|
|
162
|
+
quality: qualityValue[options.quality || 'normal'] as number
|
|
163
|
+
} as any).then((res: { path: any }) => {
|
|
164
|
+
const result = {
|
|
165
|
+
errMsg: 'takePhoto:ok',
|
|
166
|
+
tempImagePath: res.path
|
|
167
|
+
}
|
|
168
|
+
success(result)
|
|
169
|
+
complete(result)
|
|
170
|
+
}).catch(() => {
|
|
171
|
+
const result = {
|
|
172
|
+
errMsg: 'takePhoto:fail'
|
|
173
|
+
}
|
|
174
|
+
fail(result)
|
|
175
|
+
complete(result)
|
|
176
|
+
})
|
|
177
|
+
},
|
|
178
|
+
startRecord: (options: RecordOptions = {}) => {
|
|
179
|
+
let { timeout = 30, success = noop, fail = noop, complete = noop, timeoutCallback = noop } = options
|
|
180
|
+
timeout = timeout > 300 ? 300 : timeout
|
|
181
|
+
let recordTimer: NodeJS.Timeout | null = null
|
|
182
|
+
let isTimeout = false
|
|
183
|
+
try {
|
|
184
|
+
const result = {
|
|
185
|
+
errMsg: 'startRecord:ok'
|
|
186
|
+
}
|
|
187
|
+
success(result)
|
|
188
|
+
complete(result)
|
|
189
|
+
|
|
190
|
+
cameraRef.current?.startRecording?.({
|
|
191
|
+
flash,
|
|
192
|
+
onRecordingError: (error: any) => {
|
|
193
|
+
if (recordTimer) clearTimeout(recordTimer)
|
|
194
|
+
const errorResult = {
|
|
195
|
+
errMsg: 'startRecord:fail during recording',
|
|
196
|
+
error: error
|
|
197
|
+
}
|
|
198
|
+
timeoutCallback(errorResult)
|
|
199
|
+
},
|
|
200
|
+
onRecordingFinished: (video: any) => {
|
|
201
|
+
RecordRes = video
|
|
202
|
+
if (recordTimer) clearTimeout(recordTimer)
|
|
203
|
+
}
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
recordTimer = setTimeout(() => { // 超时自动停止
|
|
207
|
+
isTimeout = true
|
|
208
|
+
cameraRef.current?.stopRecording().catch(() => {
|
|
209
|
+
// 忽略停止录制时的错误
|
|
210
|
+
})
|
|
211
|
+
}, timeout * 1000)
|
|
212
|
+
} catch (error: any) {
|
|
213
|
+
if (recordTimer) clearTimeout(recordTimer)
|
|
214
|
+
const result = {
|
|
215
|
+
errMsg: 'startRecord:fail ' + (error.message || 'unknown error')
|
|
216
|
+
}
|
|
217
|
+
fail(result)
|
|
218
|
+
complete(result)
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
stopRecord: (options: StopRecordOptions = {}) => {
|
|
222
|
+
const { success = noop, fail = noop, complete = noop } = options
|
|
223
|
+
try {
|
|
224
|
+
cameraRef.current?.stopRecording().then(() => {
|
|
225
|
+
setTimeout(() => {
|
|
226
|
+
if (RecordRes) {
|
|
227
|
+
const result = {
|
|
228
|
+
errMsg: 'stopRecord:ok',
|
|
229
|
+
tempVideoPath: RecordRes?.path,
|
|
230
|
+
duration: RecordRes.duration * 1000 // 转成ms
|
|
231
|
+
}
|
|
232
|
+
RecordRes = null
|
|
233
|
+
success(result)
|
|
234
|
+
complete(result)
|
|
235
|
+
}
|
|
236
|
+
}, 200) // 延时200ms,确保录制结果已准备好
|
|
237
|
+
}).catch((e: any) => {
|
|
238
|
+
const result = {
|
|
239
|
+
errMsg: 'stopRecord:fail ' + (e.message || 'promise rejected')
|
|
240
|
+
}
|
|
241
|
+
fail(result)
|
|
242
|
+
complete(result)
|
|
243
|
+
})
|
|
244
|
+
} catch (error: any) {
|
|
245
|
+
const result = {
|
|
246
|
+
errMsg: 'stopRecord:fail ' + (error.message || 'unknown error')
|
|
247
|
+
}
|
|
248
|
+
fail(result)
|
|
249
|
+
complete(result)
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
useEffect(() => {
|
|
255
|
+
if (navigation) {
|
|
256
|
+
if (navigation && !navigation.camera) {
|
|
257
|
+
navigation.camera = camera
|
|
258
|
+
} else {
|
|
259
|
+
hasCamera.current = true
|
|
260
|
+
navigation.camera.multi = true
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
const checkCameraPermission = async () => {
|
|
264
|
+
try {
|
|
265
|
+
const cameraPermission = global?.__mpx?.config?.rnConfig?.cameraPermission
|
|
266
|
+
if (typeof cameraPermission === 'function') {
|
|
267
|
+
const permissionResult = await cameraPermission()
|
|
268
|
+
setHasPermission(permissionResult === true)
|
|
269
|
+
} else {
|
|
270
|
+
setHasPermission(true)
|
|
271
|
+
}
|
|
272
|
+
} catch (error) {
|
|
273
|
+
setHasPermission(false)
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
checkCameraPermission()
|
|
277
|
+
return () => {
|
|
278
|
+
if (navigation && navigation.camera) {
|
|
279
|
+
navigation.camera = null
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}, [])
|
|
283
|
+
|
|
284
|
+
const innerProps = useInnerProps(
|
|
285
|
+
extendObject(
|
|
286
|
+
{},
|
|
287
|
+
props,
|
|
288
|
+
layoutProps,
|
|
289
|
+
{
|
|
290
|
+
ref: cameraRef,
|
|
291
|
+
style: extendObject({}, normalStyle, layoutStyle),
|
|
292
|
+
isActive: true,
|
|
293
|
+
photo: true,
|
|
294
|
+
video: true,
|
|
295
|
+
onInitialized,
|
|
296
|
+
onStopped,
|
|
297
|
+
device,
|
|
298
|
+
format,
|
|
299
|
+
codeScanner: !isPhoto ? codeScanner : undefined,
|
|
300
|
+
zoom: zoomValue
|
|
301
|
+
}
|
|
302
|
+
),
|
|
303
|
+
[
|
|
304
|
+
'mode',
|
|
305
|
+
'resolution',
|
|
306
|
+
'frame-size',
|
|
307
|
+
'bindinitdone',
|
|
308
|
+
'bindstop',
|
|
309
|
+
'flash',
|
|
310
|
+
'bindscancode',
|
|
311
|
+
'binderror'
|
|
312
|
+
],
|
|
313
|
+
{
|
|
314
|
+
layoutRef
|
|
315
|
+
}
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
if (!hasPermission || hasCamera.current || !device) {
|
|
319
|
+
return null
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
return createElement(Camera, innerProps)
|
|
323
|
+
})
|
|
324
|
+
|
|
325
|
+
_camera.displayName = 'MpxCamera'
|
|
326
|
+
|
|
327
|
+
export default _camera
|
|
@@ -54,7 +54,7 @@ import {
|
|
|
54
54
|
NativeTouchEvent
|
|
55
55
|
} from 'react-native'
|
|
56
56
|
import { warn } from '@mpxjs/utils'
|
|
57
|
-
import { useUpdateEffect, useTransformStyle, useLayout, extendObject,
|
|
57
|
+
import { useUpdateEffect, useTransformStyle, useLayout, extendObject, isAndroid } from './utils'
|
|
58
58
|
import useInnerProps, { getCustomEvent } from './getInnerListeners'
|
|
59
59
|
import useNodesRef, { HandlerRef } from './useNodesRef'
|
|
60
60
|
import { FormContext, FormFieldValue, KeyboardAvoidContext } from './context'
|
|
@@ -188,6 +188,8 @@ const Input = forwardRef<HandlerRef<TextInput, FinalInputProps>, FinalInputProps
|
|
|
188
188
|
}
|
|
189
189
|
|
|
190
190
|
const defaultValue = parseValue(value)
|
|
191
|
+
// 微信小程序的 input 永远是单行,textAlignVertical 固定为 auto
|
|
192
|
+
// multiline 为 true 时表示是 textarea 组件复用此逻辑
|
|
191
193
|
const textAlignVertical = multiline ? 'top' : 'auto'
|
|
192
194
|
const isAutoFocus = !!autoFocus || !!focus
|
|
193
195
|
|
|
@@ -467,6 +469,12 @@ const Input = forwardRef<HandlerRef<TextInput, FinalInputProps>, FinalInputProps
|
|
|
467
469
|
: (nodeRef.current as TextInput)?.blur()
|
|
468
470
|
}, [isAutoFocus])
|
|
469
471
|
|
|
472
|
+
// 使用 multiline 来修复光标位置问题
|
|
473
|
+
// React Native 的 TextInput 在 textAlign center + placeholder 时光标会跑到右边
|
|
474
|
+
// 这个问题只在 Android 上出现
|
|
475
|
+
// 参考:https://github.com/facebook/react-native/issues/28794 (Android only)
|
|
476
|
+
const needMultilineFix = isAndroid && !multiline
|
|
477
|
+
|
|
470
478
|
const innerProps = useInnerProps(
|
|
471
479
|
extendObject(
|
|
472
480
|
{},
|
|
@@ -490,7 +498,7 @@ const Input = forwardRef<HandlerRef<TextInput, FinalInputProps>, FinalInputProps
|
|
|
490
498
|
underlineColorAndroid: 'rgba(0,0,0,0)',
|
|
491
499
|
textAlignVertical: textAlignVertical,
|
|
492
500
|
placeholderTextColor: placeholderStyle?.color,
|
|
493
|
-
multiline:
|
|
501
|
+
multiline: multiline || needMultilineFix,
|
|
494
502
|
onTouchStart,
|
|
495
503
|
onTouchEnd,
|
|
496
504
|
onFocus,
|
|
@@ -500,6 +508,7 @@ const Input = forwardRef<HandlerRef<TextInput, FinalInputProps>, FinalInputProps
|
|
|
500
508
|
onContentSizeChange,
|
|
501
509
|
onSubmitEditing: bindconfirm && onSubmitEditing
|
|
502
510
|
},
|
|
511
|
+
needMultilineFix ? { numberOfLines: 1 } : {},
|
|
503
512
|
!!multiline && confirmType === 'return' ? {} : { enterKeyHint: confirmType }
|
|
504
513
|
),
|
|
505
514
|
[
|
|
@@ -23,6 +23,7 @@ const KeyboardAvoidingView = ({ children, style, contentContainerStyle }: Keyboa
|
|
|
23
23
|
// 比如机型 iPhone 11 Pro,可能会导致显隐动画冲突
|
|
24
24
|
// 因此增加状态标记 + cancelAnimation 来优化
|
|
25
25
|
const isShow = useRef<boolean>(false)
|
|
26
|
+
const keybaordHandleTimerRef = useRef<NodeJS.Timeout | null>(null)
|
|
26
27
|
|
|
27
28
|
const animatedStyle = useAnimatedStyle(() => ({
|
|
28
29
|
// translate/position top+ overflow hidden 在 android 上时因为键盘顶起让页面高度变小,同时元素位置上移
|
|
@@ -79,7 +80,7 @@ const KeyboardAvoidingView = ({ children, style, contentContainerStyle }: Keyboa
|
|
|
79
80
|
// 重置标记位
|
|
80
81
|
keyboardAvoid.current.readyToShow = false
|
|
81
82
|
}
|
|
82
|
-
if (!keyboardAvoid?.current
|
|
83
|
+
if (!keyboardAvoid?.current) {
|
|
83
84
|
return
|
|
84
85
|
}
|
|
85
86
|
|
|
@@ -124,13 +125,23 @@ const KeyboardAvoidingView = ({ children, style, contentContainerStyle }: Keyboa
|
|
|
124
125
|
}
|
|
125
126
|
|
|
126
127
|
if (isIOS) {
|
|
127
|
-
subscriptions = [
|
|
128
|
+
subscriptions = [
|
|
129
|
+
Keyboard.addListener('keyboardWillShow', (evt: any) => {
|
|
130
|
+
if (keybaordHandleTimerRef.current) {
|
|
131
|
+
clearTimeout(keybaordHandleTimerRef.current)
|
|
132
|
+
}
|
|
133
|
+
// iphone 在input聚焦时长按滑动后会导致 show 事件先于 focus 事件发生,因此等一下,等 focus 先触发拿到 input,避免键盘出现但input没顶上去
|
|
134
|
+
keybaordHandleTimerRef.current = setTimeout(() => keybaordAvoding(evt), 32)
|
|
135
|
+
}),
|
|
136
|
+
Keyboard.addListener('keyboardWillHide', resetKeyboard)
|
|
137
|
+
]
|
|
128
138
|
} else {
|
|
129
139
|
subscriptions = [Keyboard.addListener('keyboardDidShow', keybaordAvoding), Keyboard.addListener('keyboardDidHide', resetKeyboard)]
|
|
130
140
|
}
|
|
131
141
|
|
|
132
142
|
return () => {
|
|
133
143
|
subscriptions.forEach(subscription => subscription.remove())
|
|
144
|
+
keybaordHandleTimerRef.current && clearTimeout(keybaordHandleTimerRef.current)
|
|
134
145
|
}
|
|
135
146
|
}, [keyboardAvoid])
|
|
136
147
|
|