@mpxjs/webpack-plugin 2.9.69-beta.6 → 2.9.69-beta.7
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/config.js +3 -1
- package/lib/platform/template/wx/index.js +3 -1
- package/lib/runtime/components/react/dist/mpx-swiper.jsx +54 -31
- package/lib/runtime/components/react/dist/mpx-web-view.jsx +48 -32
- package/lib/runtime/components/react/mpx-swiper.tsx +56 -36
- package/lib/runtime/components/react/mpx-web-view.tsx +61 -44
- package/package.json +1 -1
package/lib/config.js
CHANGED
|
@@ -138,7 +138,9 @@ module.exports = {
|
|
|
138
138
|
}
|
|
139
139
|
},
|
|
140
140
|
getEvent (eventName, prefix = 'on') {
|
|
141
|
-
return
|
|
141
|
+
return prefix + dash2hump(eventName.replace(/^./, (matched) => {
|
|
142
|
+
return matched.toUpperCase()
|
|
143
|
+
}))
|
|
142
144
|
},
|
|
143
145
|
defaultModelProp: 'value',
|
|
144
146
|
defaultModelEvent: 'input',
|
|
@@ -302,7 +302,9 @@ module.exports = function getSpec ({ warn, error }) {
|
|
|
302
302
|
const rPrefix = runRules(spec.event.prefix, prefix, { mode: 'ali' })
|
|
303
303
|
const rEventName = runRules(eventRules, eventName, { mode: 'ali' })
|
|
304
304
|
return {
|
|
305
|
-
name:
|
|
305
|
+
name: rPrefix + dash2hump(rEventName.replace(/^./, (matched) => {
|
|
306
|
+
return matched.toUpperCase()
|
|
307
|
+
})) + modifierStr,
|
|
306
308
|
value
|
|
307
309
|
}
|
|
308
310
|
},
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { View } from 'react-native';
|
|
1
|
+
import { AppState, View } from 'react-native';
|
|
2
2
|
import { GestureDetector, Gesture } from 'react-native-gesture-handler';
|
|
3
3
|
import Animated, { useAnimatedStyle, useSharedValue, withTiming, Easing, runOnJS, useAnimatedReaction, cancelAnimation } from 'react-native-reanimated';
|
|
4
4
|
import React, { forwardRef, useRef, useEffect, useMemo } from 'react';
|
|
@@ -70,7 +70,7 @@ const easeMap = {
|
|
|
70
70
|
easeInOutCubic: Easing.inOut(Easing.cubic)
|
|
71
71
|
};
|
|
72
72
|
const SwiperWrapper = forwardRef((props, ref) => {
|
|
73
|
-
const { 'indicator-dots': showsPagination, 'indicator-color': dotColor = 'rgba(0, 0, 0, .3)', 'indicator-active-color': activeDotColor = '#000000', 'enable-var': enableVar = false, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, 'external-var-context': externalVarContext, style = {}, autoplay, circular } = props;
|
|
73
|
+
const { 'indicator-dots': showsPagination, 'indicator-color': dotColor = 'rgba(0, 0, 0, .3)', 'indicator-active-color': activeDotColor = '#000000', 'enable-var': enableVar = false, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, 'external-var-context': externalVarContext, style = {}, autoplay = false, circular = false } = props;
|
|
74
74
|
const easeingFunc = props['easing-function'] || 'default';
|
|
75
75
|
const easeDuration = props.duration || 500;
|
|
76
76
|
const horizontal = props.vertical !== undefined ? !props.vertical : true;
|
|
@@ -86,15 +86,15 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
86
86
|
});
|
|
87
87
|
const { textStyle } = splitStyle(normalStyle);
|
|
88
88
|
const { textProps } = splitProps(props);
|
|
89
|
-
const preMargin = props['previous-margin'] ?
|
|
90
|
-
const nextMargin = props['next-margin'] ?
|
|
91
|
-
const
|
|
89
|
+
const preMargin = props['previous-margin'] ? global.__formatValue(props['previous-margin']) : 0;
|
|
90
|
+
const nextMargin = props['next-margin'] ? global.__formatValue(props['next-margin']) : 0;
|
|
91
|
+
const preMarginShared = useSharedValue(preMargin);
|
|
92
92
|
const nextMarginShared = useSharedValue(nextMargin);
|
|
93
|
-
const autoplayShared = useSharedValue(autoplay
|
|
93
|
+
const autoplayShared = useSharedValue(autoplay);
|
|
94
94
|
// 默认前后补位的元素个数
|
|
95
95
|
const patchElmNum = circular ? (preMargin ? 2 : 1) : 0;
|
|
96
96
|
const patchElmNumShared = useSharedValue(patchElmNum);
|
|
97
|
-
const circularShared = useSharedValue(circular
|
|
97
|
+
const circularShared = useSharedValue(circular);
|
|
98
98
|
const children = Array.isArray(props.children) ? props.children.filter(child => child) : (props.children ? [props.children] : []);
|
|
99
99
|
// 对有变化的变量,在worklet中只能使用sharedValue变量,useRef不能更新
|
|
100
100
|
const childrenLength = useSharedValue(children.length);
|
|
@@ -121,6 +121,7 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
121
121
|
const moveTime = useSharedValue(0);
|
|
122
122
|
const timerId = useRef(0);
|
|
123
123
|
const intervalTimer = props.interval || 500;
|
|
124
|
+
const appState = useRef(AppState.currentState);
|
|
124
125
|
const {
|
|
125
126
|
// 存储layout布局信息
|
|
126
127
|
layoutRef, layoutProps, layoutStyle } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef, onLayout: onWrapperLayout });
|
|
@@ -234,7 +235,7 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
234
235
|
}
|
|
235
236
|
const { loop, pauseLoop, resumeLoop } = useMemo(() => {
|
|
236
237
|
function createAutoPlay() {
|
|
237
|
-
if (!step.value)
|
|
238
|
+
if (!step.value || appState.current !== 'active')
|
|
238
239
|
return;
|
|
239
240
|
let targetOffset = 0;
|
|
240
241
|
let nextIndex = currentIndex.value;
|
|
@@ -245,7 +246,7 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
245
246
|
return;
|
|
246
247
|
}
|
|
247
248
|
nextIndex += 1;
|
|
248
|
-
// targetOffset = -nextIndex * step.value -
|
|
249
|
+
// targetOffset = -nextIndex * step.value - preMarginShared.value
|
|
249
250
|
targetOffset = -nextIndex * step.value;
|
|
250
251
|
offset.value = withTiming(targetOffset, {
|
|
251
252
|
duration: easeDuration,
|
|
@@ -259,12 +260,12 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
259
260
|
// 默认向右, 向下
|
|
260
261
|
if (nextIndex === childrenLength.value - 1) {
|
|
261
262
|
nextIndex = 0;
|
|
262
|
-
targetOffset = -(childrenLength.value + patchElmNumShared.value) * step.value +
|
|
263
|
+
targetOffset = -(childrenLength.value + patchElmNumShared.value) * step.value + preMarginShared.value;
|
|
263
264
|
// 执行动画到下一帧
|
|
264
265
|
offset.value = withTiming(targetOffset, {
|
|
265
266
|
duration: easeDuration
|
|
266
267
|
}, () => {
|
|
267
|
-
const initOffset = -step.value * patchElmNumShared.value +
|
|
268
|
+
const initOffset = -step.value * patchElmNumShared.value + preMarginShared.value;
|
|
268
269
|
// 将开始位置设置为真正的位置
|
|
269
270
|
offset.value = initOffset;
|
|
270
271
|
currentIndex.value = nextIndex;
|
|
@@ -273,7 +274,7 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
273
274
|
}
|
|
274
275
|
else {
|
|
275
276
|
nextIndex = currentIndex.value + 1;
|
|
276
|
-
targetOffset = -(nextIndex + patchElmNumShared.value) * step.value +
|
|
277
|
+
targetOffset = -(nextIndex + patchElmNumShared.value) * step.value + preMarginShared.value;
|
|
277
278
|
// 执行动画到下一帧
|
|
278
279
|
offset.value = withTiming(targetOffset, {
|
|
279
280
|
duration: easeDuration,
|
|
@@ -288,7 +289,9 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
288
289
|
// loop在JS线程中调用,createAutoPlay + useEffect中
|
|
289
290
|
function loop() {
|
|
290
291
|
timerId.current && clearTimeout(timerId.current);
|
|
291
|
-
|
|
292
|
+
if (appState.current === 'active') {
|
|
293
|
+
timerId.current = setTimeout(createAutoPlay, intervalTimer);
|
|
294
|
+
}
|
|
292
295
|
}
|
|
293
296
|
function pauseLoop() {
|
|
294
297
|
timerId.current && clearTimeout(timerId.current);
|
|
@@ -356,15 +359,30 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
356
359
|
runOnJS(handleSwiperChange)(newIndex);
|
|
357
360
|
}
|
|
358
361
|
});
|
|
362
|
+
// 监听切换前后台,默认切换到后台JS执行不会立即停止定时器还在
|
|
363
|
+
useEffect(() => {
|
|
364
|
+
const subscription = AppState.addEventListener('change', nextAppState => {
|
|
365
|
+
appState.current = nextAppState;
|
|
366
|
+
if (nextAppState === 'active' && autoplayShared.value && childrenLength.value > 1) {
|
|
367
|
+
loop();
|
|
368
|
+
}
|
|
369
|
+
else {
|
|
370
|
+
appState.current = nextAppState;
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
return () => {
|
|
374
|
+
subscription.remove();
|
|
375
|
+
};
|
|
376
|
+
}, []);
|
|
359
377
|
useEffect(() => {
|
|
360
378
|
let patchStep = 0;
|
|
361
|
-
if (preMargin !==
|
|
362
|
-
patchStep += preMargin -
|
|
379
|
+
if (preMargin !== preMarginShared.value) {
|
|
380
|
+
patchStep += preMargin - preMarginShared.value;
|
|
363
381
|
}
|
|
364
382
|
if (nextMargin !== nextMarginShared.value) {
|
|
365
383
|
patchStep += nextMargin - nextMarginShared.value;
|
|
366
384
|
}
|
|
367
|
-
|
|
385
|
+
preMarginShared.value = preMargin;
|
|
368
386
|
nextMarginShared.value = nextMargin;
|
|
369
387
|
const newStep = step.value - patchStep;
|
|
370
388
|
if (step.value !== newStep) {
|
|
@@ -374,20 +392,25 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
374
392
|
}, [preMargin, nextMargin]);
|
|
375
393
|
useEffect(() => {
|
|
376
394
|
childrenLength.value = children.length;
|
|
395
|
+
pauseLoop();
|
|
377
396
|
if (children.length - 1 < currentIndex.value) {
|
|
378
|
-
pauseLoop();
|
|
379
397
|
currentIndex.value = 0;
|
|
380
398
|
offset.value = getOffset(0, step.value);
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
399
|
+
}
|
|
400
|
+
else {
|
|
401
|
+
// children变化-其他属性都不变化(比如从1变化到3或者从3变到1, 在circular的情况下offset是需要更新的)
|
|
402
|
+
currentIndex.value = props.current || 0;
|
|
403
|
+
offset.value = getOffset(props.current || 0, step.value);
|
|
404
|
+
}
|
|
405
|
+
if (autoplay && children.length > 1) {
|
|
406
|
+
loop();
|
|
384
407
|
}
|
|
385
408
|
}, [children.length]);
|
|
386
409
|
useEffect(() => {
|
|
387
410
|
updateCurrent(props.current || 0, step.value);
|
|
388
411
|
}, [props.current]);
|
|
389
412
|
useEffect(() => {
|
|
390
|
-
autoplayShared.value = autoplay
|
|
413
|
+
autoplayShared.value = autoplay;
|
|
391
414
|
updateAutoplay();
|
|
392
415
|
return () => {
|
|
393
416
|
if (autoplay) {
|
|
@@ -397,7 +420,7 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
397
420
|
}, [autoplay]);
|
|
398
421
|
useEffect(() => {
|
|
399
422
|
if (circular !== circularShared.value) {
|
|
400
|
-
circularShared.value = circular
|
|
423
|
+
circularShared.value = circular;
|
|
401
424
|
patchElmNumShared.value = circular ? (preMargin ? 2 : 1) : 0;
|
|
402
425
|
offset.value = getOffset(currentIndex.value, step.value);
|
|
403
426
|
}
|
|
@@ -413,7 +436,7 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
413
436
|
let isCriticalItem = false;
|
|
414
437
|
// 真实滚动到的偏移量坐标
|
|
415
438
|
let moveToTargetPos = 0;
|
|
416
|
-
const currentOffset = translation < 0 ? offset.value -
|
|
439
|
+
const currentOffset = translation < 0 ? offset.value - preMarginShared.value : offset.value + preMarginShared.value;
|
|
417
440
|
const computedIndex = Math.abs(currentOffset) / step.value;
|
|
418
441
|
const moveToIndex = translation < 0 ? Math.ceil(computedIndex) : Math.floor(computedIndex);
|
|
419
442
|
// 实际应该定位的索引值
|
|
@@ -424,19 +447,19 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
424
447
|
else {
|
|
425
448
|
if (moveToIndex >= childrenLength.value + patchElmNumShared.value) {
|
|
426
449
|
selectedIndex = moveToIndex - (childrenLength.value + patchElmNumShared.value);
|
|
427
|
-
resetOffsetPos = (selectedIndex + patchElmNumShared.value) * step.value -
|
|
428
|
-
moveToTargetPos = moveToIndex * step.value -
|
|
450
|
+
resetOffsetPos = (selectedIndex + patchElmNumShared.value) * step.value - preMarginShared.value;
|
|
451
|
+
moveToTargetPos = moveToIndex * step.value - preMarginShared.value;
|
|
429
452
|
isCriticalItem = true;
|
|
430
453
|
}
|
|
431
454
|
else if (moveToIndex <= patchElmNumShared.value - 1) {
|
|
432
455
|
selectedIndex = moveToIndex === 0 ? childrenLength.value - patchElmNumShared.value : childrenLength.value - 1;
|
|
433
|
-
resetOffsetPos = (selectedIndex + patchElmNumShared.value) * step.value -
|
|
434
|
-
moveToTargetPos = moveToIndex * step.value -
|
|
456
|
+
resetOffsetPos = (selectedIndex + patchElmNumShared.value) * step.value - preMarginShared.value;
|
|
457
|
+
moveToTargetPos = moveToIndex * step.value - preMarginShared.value;
|
|
435
458
|
isCriticalItem = true;
|
|
436
459
|
}
|
|
437
460
|
else {
|
|
438
461
|
selectedIndex = moveToIndex - patchElmNumShared.value;
|
|
439
|
-
moveToTargetPos = moveToIndex * step.value -
|
|
462
|
+
moveToTargetPos = moveToIndex * step.value - preMarginShared.value;
|
|
440
463
|
}
|
|
441
464
|
}
|
|
442
465
|
return {
|
|
@@ -495,11 +518,11 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
495
518
|
// 向右滑动的back:trans < 0, 向左滑动的back: trans < 0
|
|
496
519
|
let currentOffset = Math.abs(offset.value);
|
|
497
520
|
if (circularShared.value) {
|
|
498
|
-
currentOffset += translation < 0 ?
|
|
521
|
+
currentOffset += translation < 0 ? preMarginShared.value : -preMarginShared.value;
|
|
499
522
|
}
|
|
500
523
|
const curIndex = currentOffset / step.value;
|
|
501
524
|
const moveToIndex = (translation < 0 ? Math.floor(curIndex) : Math.ceil(curIndex)) - patchElmNumShared.value;
|
|
502
|
-
const targetOffset = -(moveToIndex + patchElmNumShared.value) * step.value + (circularShared.value ?
|
|
525
|
+
const targetOffset = -(moveToIndex + patchElmNumShared.value) * step.value + (circularShared.value ? preMarginShared.value : 0);
|
|
503
526
|
offset.value = withTiming(targetOffset, {
|
|
504
527
|
duration: easeDuration,
|
|
505
528
|
easing: easeMap[easeingFunc]
|
|
@@ -515,7 +538,7 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
515
538
|
const currentOffset = Math.abs(offset.value);
|
|
516
539
|
let preOffset = (currentIndex.value + patchElmNumShared.value) * step.value;
|
|
517
540
|
if (circularShared.value) {
|
|
518
|
-
preOffset -=
|
|
541
|
+
preOffset -= preMarginShared.value;
|
|
519
542
|
}
|
|
520
543
|
// 正常事件中拿到的transition值(正向滑动<0,倒着滑>0)
|
|
521
544
|
const diffOffset = preOffset - currentOffset;
|
|
@@ -5,7 +5,7 @@ import { getCustomEvent } from './getInnerListeners';
|
|
|
5
5
|
import { promisify, redirectTo, navigateTo, navigateBack, reLaunch, switchTab } from '@mpxjs/api-proxy';
|
|
6
6
|
import { WebView } from 'react-native-webview';
|
|
7
7
|
import useNodesRef from './useNodesRef';
|
|
8
|
-
import { getCurrentPage
|
|
8
|
+
import { getCurrentPage } from './utils';
|
|
9
9
|
import { useNavigation } from '@react-navigation/native';
|
|
10
10
|
import { RouteContext } from './context';
|
|
11
11
|
import { BackHandler, StyleSheet, View, Text } from 'react-native';
|
|
@@ -54,6 +54,7 @@ const _WebView = forwardRef((props, ref) => {
|
|
|
54
54
|
const [pageLoadErr, setPageLoadErr] = useState(false);
|
|
55
55
|
const currentPage = useMemo(() => getCurrentPage(pageId), [pageId]);
|
|
56
56
|
const webViewRef = useRef(null);
|
|
57
|
+
const isLoaded = useRef(false);
|
|
57
58
|
const defaultWebViewStyle = {
|
|
58
59
|
position: 'absolute',
|
|
59
60
|
left: 0,
|
|
@@ -99,27 +100,6 @@ const _WebView = forwardRef((props, ref) => {
|
|
|
99
100
|
if (!src) {
|
|
100
101
|
return null;
|
|
101
102
|
}
|
|
102
|
-
const _load = function (res) {
|
|
103
|
-
const result = {
|
|
104
|
-
type: 'load',
|
|
105
|
-
timeStamp: res.timeStamp,
|
|
106
|
-
detail: {
|
|
107
|
-
src: res.nativeEvent?.url
|
|
108
|
-
}
|
|
109
|
-
};
|
|
110
|
-
bindload?.(result);
|
|
111
|
-
};
|
|
112
|
-
const _error = function (res) {
|
|
113
|
-
setPageLoadErr(true);
|
|
114
|
-
const result = {
|
|
115
|
-
type: 'error',
|
|
116
|
-
timeStamp: res.timeStamp,
|
|
117
|
-
detail: {
|
|
118
|
-
src: ''
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
binderror && binderror(result);
|
|
122
|
-
};
|
|
123
103
|
const _reload = function () {
|
|
124
104
|
setPageLoadErr(false);
|
|
125
105
|
};
|
|
@@ -251,22 +231,58 @@ const _WebView = forwardRef((props, ref) => {
|
|
|
251
231
|
}
|
|
252
232
|
});
|
|
253
233
|
};
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
234
|
+
let isLoadError = false;
|
|
235
|
+
let fristLoaded = false;
|
|
236
|
+
let statusCode = '';
|
|
237
|
+
const onLoadEnd = function (res) {
|
|
238
|
+
fristLoaded = true;
|
|
239
|
+
isLoaded.current = true;
|
|
240
|
+
const src = res.nativeEvent?.url;
|
|
241
|
+
if (isLoadError) {
|
|
242
|
+
isLoadError = false;
|
|
243
|
+
isNavigateBack.current = false;
|
|
244
|
+
const result = {
|
|
245
|
+
type: 'error',
|
|
246
|
+
timeStamp: res.timeStamp,
|
|
247
|
+
detail: {
|
|
248
|
+
src,
|
|
249
|
+
statusCode
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
binderror && binderror(result);
|
|
253
|
+
}
|
|
254
|
+
else {
|
|
255
|
+
const result = {
|
|
256
|
+
type: 'load',
|
|
257
|
+
timeStamp: res.timeStamp,
|
|
258
|
+
detail: {
|
|
259
|
+
src
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
bindload?.(result);
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
const onHttpError = function (res) {
|
|
266
|
+
isLoadError = true;
|
|
267
|
+
statusCode = res.nativeEvent?.statusCode;
|
|
268
|
+
};
|
|
269
|
+
const onError = function () {
|
|
270
|
+
statusCode = '';
|
|
271
|
+
isLoadError = true;
|
|
272
|
+
if (!fristLoaded) {
|
|
273
|
+
setPageLoadErr(true);
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
const onLoadStart = function () {
|
|
277
|
+
isLoaded.current = false;
|
|
278
|
+
};
|
|
263
279
|
return (<Portal key={pageLoadErr ? 'error' : 'webview'}>
|
|
264
280
|
{pageLoadErr
|
|
265
281
|
? (<View style={[styles.loadErrorContext, defaultWebViewStyle]}>
|
|
266
282
|
<View style={styles.loadErrorText}><Text style={{ fontSize: 14, color: '#999999' }}>{currentErrorText.text}</Text></View>
|
|
267
283
|
<View style={styles.loadErrorButton} onTouchEnd={_reload}><Text style={{ fontSize: 12, color: '#666666' }}>{currentErrorText.button}</Text></View>
|
|
268
284
|
</View>)
|
|
269
|
-
: (<WebView style={defaultWebViewStyle} source={{ uri: src }} ref={webViewRef} javaScriptEnabled={true} onNavigationStateChange={_changeUrl} onMessage={_message} injectedJavaScript={injectedJavaScript} onLoadProgress={_onLoadProgress}
|
|
285
|
+
: (<WebView style={defaultWebViewStyle} source={{ uri: src }} pointerEvents={isLoaded ? 'auto' : 'none'} ref={webViewRef} javaScriptEnabled={true} onNavigationStateChange={_changeUrl} onMessage={_message} injectedJavaScript={injectedJavaScript} onLoadProgress={_onLoadProgress} onLoadEnd={onLoadEnd} onHttpError={onHttpError} onError={onError} onLoadStart={onLoadStart} allowsBackForwardNavigationGestures={true}></WebView>)}
|
|
270
286
|
</Portal>);
|
|
271
287
|
});
|
|
272
288
|
_WebView.displayName = 'MpxWebview';
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { View, NativeSyntheticEvent, LayoutChangeEvent } from 'react-native'
|
|
1
|
+
import { AppState, View, NativeSyntheticEvent, LayoutChangeEvent } from 'react-native'
|
|
2
2
|
import { GestureDetector, Gesture } from 'react-native-gesture-handler'
|
|
3
3
|
import Animated, { useAnimatedStyle, useSharedValue, withTiming, Easing, runOnJS, useAnimatedReaction, cancelAnimation } from 'react-native-reanimated'
|
|
4
4
|
|
|
5
|
-
import React, { JSX, forwardRef, useRef, useEffect, ReactNode, ReactElement,
|
|
5
|
+
import React, { JSX, forwardRef, useRef, useEffect, ReactNode, ReactElement, useMemo } from 'react'
|
|
6
6
|
import useInnerProps, { getCustomEvent } from './getInnerListeners'
|
|
7
7
|
import useNodesRef, { HandlerRef } from './useNodesRef' // 引入辅助函数
|
|
8
8
|
import { useTransformStyle, splitStyle, splitProps, useLayout, wrapChildren } from './utils'
|
|
@@ -135,8 +135,8 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
135
135
|
'parent-height': parentHeight,
|
|
136
136
|
'external-var-context': externalVarContext,
|
|
137
137
|
style = {},
|
|
138
|
-
autoplay,
|
|
139
|
-
circular
|
|
138
|
+
autoplay = false,
|
|
139
|
+
circular = false
|
|
140
140
|
} = props
|
|
141
141
|
const easeingFunc = props['easing-function'] || 'default'
|
|
142
142
|
const easeDuration = props.duration || 500
|
|
@@ -160,15 +160,15 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
160
160
|
})
|
|
161
161
|
const { textStyle } = splitStyle(normalStyle)
|
|
162
162
|
const { textProps } = splitProps(props)
|
|
163
|
-
const preMargin = props['previous-margin'] ?
|
|
164
|
-
const nextMargin = props['next-margin'] ?
|
|
165
|
-
const
|
|
163
|
+
const preMargin = props['previous-margin'] ? global.__formatValue(props['previous-margin']) as number : 0
|
|
164
|
+
const nextMargin = props['next-margin'] ? global.__formatValue(props['next-margin']) as number : 0
|
|
165
|
+
const preMarginShared = useSharedValue(preMargin)
|
|
166
166
|
const nextMarginShared = useSharedValue(nextMargin)
|
|
167
|
-
const autoplayShared = useSharedValue(autoplay
|
|
167
|
+
const autoplayShared = useSharedValue(autoplay)
|
|
168
168
|
// 默认前后补位的元素个数
|
|
169
169
|
const patchElmNum = circular ? (preMargin ? 2 : 1) : 0
|
|
170
170
|
const patchElmNumShared = useSharedValue(patchElmNum)
|
|
171
|
-
const circularShared = useSharedValue(circular
|
|
171
|
+
const circularShared = useSharedValue(circular)
|
|
172
172
|
const children = Array.isArray(props.children) ? props.children.filter(child => child) : (props.children ? [props.children] : [])
|
|
173
173
|
// 对有变化的变量,在worklet中只能使用sharedValue变量,useRef不能更新
|
|
174
174
|
const childrenLength = useSharedValue(children.length)
|
|
@@ -195,6 +195,7 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
195
195
|
const moveTime = useSharedValue(0)
|
|
196
196
|
const timerId = useRef(0 as number | ReturnType<typeof setTimeout>)
|
|
197
197
|
const intervalTimer = props.interval || 500
|
|
198
|
+
const appState = useRef(AppState.currentState)
|
|
198
199
|
const {
|
|
199
200
|
// 存储layout布局信息
|
|
200
201
|
layoutRef,
|
|
@@ -312,9 +313,9 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
312
313
|
return (<SwiperContext.Provider value={contextValue}>{arrChildren}</SwiperContext.Provider>)
|
|
313
314
|
}
|
|
314
315
|
|
|
315
|
-
const { loop, pauseLoop, resumeLoop} = useMemo(() => {
|
|
316
|
+
const { loop, pauseLoop, resumeLoop } = useMemo(() => {
|
|
316
317
|
function createAutoPlay () {
|
|
317
|
-
if (!step.value) return
|
|
318
|
+
if (!step.value || appState.current !== 'active') return
|
|
318
319
|
let targetOffset = 0
|
|
319
320
|
let nextIndex = currentIndex.value
|
|
320
321
|
if (!circularShared.value) {
|
|
@@ -324,7 +325,7 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
324
325
|
return
|
|
325
326
|
}
|
|
326
327
|
nextIndex += 1
|
|
327
|
-
// targetOffset = -nextIndex * step.value -
|
|
328
|
+
// targetOffset = -nextIndex * step.value - preMarginShared.value
|
|
328
329
|
targetOffset = -nextIndex * step.value
|
|
329
330
|
offset.value = withTiming(targetOffset, {
|
|
330
331
|
duration: easeDuration,
|
|
@@ -337,12 +338,12 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
337
338
|
// 默认向右, 向下
|
|
338
339
|
if (nextIndex === childrenLength.value - 1) {
|
|
339
340
|
nextIndex = 0
|
|
340
|
-
targetOffset = -(childrenLength.value + patchElmNumShared.value) * step.value +
|
|
341
|
+
targetOffset = -(childrenLength.value + patchElmNumShared.value) * step.value + preMarginShared.value
|
|
341
342
|
// 执行动画到下一帧
|
|
342
343
|
offset.value = withTiming(targetOffset, {
|
|
343
344
|
duration: easeDuration
|
|
344
345
|
}, () => {
|
|
345
|
-
const initOffset = -step.value * patchElmNumShared.value +
|
|
346
|
+
const initOffset = -step.value * patchElmNumShared.value + preMarginShared.value
|
|
346
347
|
// 将开始位置设置为真正的位置
|
|
347
348
|
offset.value = initOffset
|
|
348
349
|
currentIndex.value = nextIndex
|
|
@@ -350,7 +351,7 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
350
351
|
})
|
|
351
352
|
} else {
|
|
352
353
|
nextIndex = currentIndex.value + 1
|
|
353
|
-
targetOffset = -(nextIndex + patchElmNumShared.value) * step.value +
|
|
354
|
+
targetOffset = -(nextIndex + patchElmNumShared.value) * step.value + preMarginShared.value
|
|
354
355
|
// 执行动画到下一帧
|
|
355
356
|
offset.value = withTiming(targetOffset, {
|
|
356
357
|
duration: easeDuration,
|
|
@@ -366,7 +367,9 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
366
367
|
// loop在JS线程中调用,createAutoPlay + useEffect中
|
|
367
368
|
function loop () {
|
|
368
369
|
timerId.current && clearTimeout(timerId.current)
|
|
369
|
-
|
|
370
|
+
if (appState.current === 'active') {
|
|
371
|
+
timerId.current = setTimeout(createAutoPlay, intervalTimer)
|
|
372
|
+
}
|
|
370
373
|
}
|
|
371
374
|
|
|
372
375
|
function pauseLoop () {
|
|
@@ -434,16 +437,30 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
434
437
|
runOnJS(handleSwiperChange)(newIndex)
|
|
435
438
|
}
|
|
436
439
|
})
|
|
440
|
+
// 监听切换前后台,默认切换到后台JS执行不会立即停止定时器还在
|
|
441
|
+
useEffect(() => {
|
|
442
|
+
const subscription = AppState.addEventListener('change', nextAppState => {
|
|
443
|
+
appState.current = nextAppState
|
|
444
|
+
if (nextAppState === 'active' && autoplayShared.value && childrenLength.value > 1) {
|
|
445
|
+
loop()
|
|
446
|
+
} else {
|
|
447
|
+
appState.current = nextAppState
|
|
448
|
+
}
|
|
449
|
+
})
|
|
450
|
+
return () => {
|
|
451
|
+
subscription.remove()
|
|
452
|
+
}
|
|
453
|
+
}, [])
|
|
437
454
|
|
|
438
455
|
useEffect(() => {
|
|
439
456
|
let patchStep = 0
|
|
440
|
-
if (preMargin !==
|
|
441
|
-
patchStep += preMargin -
|
|
457
|
+
if (preMargin !== preMarginShared.value) {
|
|
458
|
+
patchStep += preMargin - preMarginShared.value
|
|
442
459
|
}
|
|
443
460
|
if (nextMargin !== nextMarginShared.value) {
|
|
444
461
|
patchStep += nextMargin - nextMarginShared.value
|
|
445
462
|
}
|
|
446
|
-
|
|
463
|
+
preMarginShared.value = preMargin
|
|
447
464
|
nextMarginShared.value = nextMargin
|
|
448
465
|
const newStep = step.value - patchStep
|
|
449
466
|
if (step.value !== newStep) {
|
|
@@ -454,13 +471,17 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
454
471
|
|
|
455
472
|
useEffect(() => {
|
|
456
473
|
childrenLength.value = children.length
|
|
474
|
+
pauseLoop()
|
|
457
475
|
if (children.length - 1 < currentIndex.value) {
|
|
458
|
-
pauseLoop()
|
|
459
476
|
currentIndex.value = 0
|
|
460
477
|
offset.value = getOffset(0, step.value)
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
478
|
+
} else {
|
|
479
|
+
// children变化-其他属性都不变化(比如从1变化到3或者从3变到1, 在circular的情况下offset是需要更新的)
|
|
480
|
+
currentIndex.value = props.current || 0
|
|
481
|
+
offset.value = getOffset(props.current || 0, step.value)
|
|
482
|
+
}
|
|
483
|
+
if (autoplay && children.length > 1) {
|
|
484
|
+
loop()
|
|
464
485
|
}
|
|
465
486
|
}, [children.length])
|
|
466
487
|
|
|
@@ -469,7 +490,7 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
469
490
|
}, [props.current])
|
|
470
491
|
|
|
471
492
|
useEffect(() => {
|
|
472
|
-
autoplayShared.value = autoplay
|
|
493
|
+
autoplayShared.value = autoplay
|
|
473
494
|
updateAutoplay()
|
|
474
495
|
return () => {
|
|
475
496
|
if (autoplay) {
|
|
@@ -480,7 +501,7 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
480
501
|
|
|
481
502
|
useEffect(() => {
|
|
482
503
|
if (circular !== circularShared.value) {
|
|
483
|
-
circularShared.value = circular
|
|
504
|
+
circularShared.value = circular
|
|
484
505
|
patchElmNumShared.value = circular ? (preMargin ? 2 : 1) : 0
|
|
485
506
|
offset.value = getOffset(currentIndex.value, step.value)
|
|
486
507
|
}
|
|
@@ -497,7 +518,7 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
497
518
|
let isCriticalItem = false
|
|
498
519
|
// 真实滚动到的偏移量坐标
|
|
499
520
|
let moveToTargetPos = 0
|
|
500
|
-
const currentOffset = translation < 0 ? offset.value -
|
|
521
|
+
const currentOffset = translation < 0 ? offset.value - preMarginShared.value : offset.value + preMarginShared.value
|
|
501
522
|
const computedIndex = Math.abs(currentOffset) / step.value
|
|
502
523
|
const moveToIndex = translation < 0 ? Math.ceil(computedIndex) : Math.floor(computedIndex)
|
|
503
524
|
// 实际应该定位的索引值
|
|
@@ -507,17 +528,17 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
507
528
|
} else {
|
|
508
529
|
if (moveToIndex >= childrenLength.value + patchElmNumShared.value) {
|
|
509
530
|
selectedIndex = moveToIndex - (childrenLength.value + patchElmNumShared.value)
|
|
510
|
-
resetOffsetPos = (selectedIndex + patchElmNumShared.value) * step.value -
|
|
511
|
-
moveToTargetPos = moveToIndex * step.value -
|
|
531
|
+
resetOffsetPos = (selectedIndex + patchElmNumShared.value) * step.value - preMarginShared.value
|
|
532
|
+
moveToTargetPos = moveToIndex * step.value - preMarginShared.value
|
|
512
533
|
isCriticalItem = true
|
|
513
534
|
} else if (moveToIndex <= patchElmNumShared.value - 1) {
|
|
514
535
|
selectedIndex = moveToIndex === 0 ? childrenLength.value - patchElmNumShared.value : childrenLength.value - 1
|
|
515
|
-
resetOffsetPos = (selectedIndex + patchElmNumShared.value) * step.value -
|
|
516
|
-
moveToTargetPos = moveToIndex * step.value -
|
|
536
|
+
resetOffsetPos = (selectedIndex + patchElmNumShared.value) * step.value - preMarginShared.value
|
|
537
|
+
moveToTargetPos = moveToIndex * step.value - preMarginShared.value
|
|
517
538
|
isCriticalItem = true
|
|
518
539
|
} else {
|
|
519
540
|
selectedIndex = moveToIndex - patchElmNumShared.value
|
|
520
|
-
moveToTargetPos = moveToIndex * step.value -
|
|
541
|
+
moveToTargetPos = moveToIndex * step.value - preMarginShared.value
|
|
521
542
|
}
|
|
522
543
|
}
|
|
523
544
|
return {
|
|
@@ -573,11 +594,11 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
573
594
|
// 向右滑动的back:trans < 0, 向左滑动的back: trans < 0
|
|
574
595
|
let currentOffset = Math.abs(offset.value)
|
|
575
596
|
if (circularShared.value) {
|
|
576
|
-
currentOffset += translation < 0 ?
|
|
597
|
+
currentOffset += translation < 0 ? preMarginShared.value : -preMarginShared.value
|
|
577
598
|
}
|
|
578
599
|
const curIndex = currentOffset / step.value
|
|
579
600
|
const moveToIndex = (translation < 0 ? Math.floor(curIndex) : Math.ceil(curIndex)) - patchElmNumShared.value
|
|
580
|
-
const targetOffset = -(moveToIndex + patchElmNumShared.value) * step.value + (circularShared.value ?
|
|
601
|
+
const targetOffset = -(moveToIndex + patchElmNumShared.value) * step.value + (circularShared.value ? preMarginShared.value : 0)
|
|
581
602
|
offset.value = withTiming(targetOffset, {
|
|
582
603
|
duration: easeDuration,
|
|
583
604
|
easing: easeMap[easeingFunc]
|
|
@@ -593,7 +614,7 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
593
614
|
const currentOffset = Math.abs(offset.value)
|
|
594
615
|
let preOffset = (currentIndex.value + patchElmNumShared.value) * step.value
|
|
595
616
|
if (circularShared.value) {
|
|
596
|
-
preOffset -=
|
|
617
|
+
preOffset -= preMarginShared.value
|
|
597
618
|
}
|
|
598
619
|
// 正常事件中拿到的transition值(正向滑动<0,倒着滑>0)
|
|
599
620
|
const diffOffset = preOffset - currentOffset
|
|
@@ -611,7 +632,6 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
611
632
|
// 移动的距离
|
|
612
633
|
const { translation } = eventData
|
|
613
634
|
const elementsLength = step.value * childrenLength.value
|
|
614
|
-
|
|
615
635
|
let isBoundary = false
|
|
616
636
|
let resetOffset = 0
|
|
617
637
|
// Y轴向下滚动, transDistance > 0, 向上滚动 < 0 X轴向左滚动, transDistance > 0
|
|
@@ -678,7 +698,7 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
678
698
|
})
|
|
679
699
|
.onTouchesUp((e) => {
|
|
680
700
|
'worklet'
|
|
681
|
-
if(touchfinish.value) return
|
|
701
|
+
if (touchfinish.value) return
|
|
682
702
|
const touchEventData = e.changedTouches[0]
|
|
683
703
|
const moveDistance = touchEventData[strAbso] - moveTranstion.value
|
|
684
704
|
touchfinish.value = true
|
|
@@ -5,8 +5,8 @@ import { getCustomEvent } from './getInnerListeners'
|
|
|
5
5
|
import { promisify, redirectTo, navigateTo, navigateBack, reLaunch, switchTab } from '@mpxjs/api-proxy'
|
|
6
6
|
import { WebView } from 'react-native-webview'
|
|
7
7
|
import useNodesRef, { HandlerRef } from './useNodesRef'
|
|
8
|
-
import { getCurrentPage
|
|
9
|
-
import {
|
|
8
|
+
import { getCurrentPage } from './utils'
|
|
9
|
+
import { WebViewMessageEvent, WebViewNavigation, WebViewProgressEvent, WebViewHttpErrorEvent, WebViewEvent } from 'react-native-webview/lib/WebViewTypes'
|
|
10
10
|
import { useNavigation } from '@react-navigation/native'
|
|
11
11
|
import { RouteContext } from './context'
|
|
12
12
|
import { BackHandler, StyleSheet, View, Text, Platform } from 'react-native'
|
|
@@ -99,6 +99,7 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((pr
|
|
|
99
99
|
const [pageLoadErr, setPageLoadErr] = useState<boolean>(false)
|
|
100
100
|
const currentPage = useMemo(() => getCurrentPage(pageId), [pageId])
|
|
101
101
|
const webViewRef = useRef<WebView>(null)
|
|
102
|
+
const isLoaded = useRef<boolean>(false)
|
|
102
103
|
const defaultWebViewStyle = {
|
|
103
104
|
position: 'absolute' as 'absolute' | 'relative' | 'static',
|
|
104
105
|
left: 0 as number,
|
|
@@ -151,28 +152,6 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((pr
|
|
|
151
152
|
return null
|
|
152
153
|
}
|
|
153
154
|
|
|
154
|
-
const _load = function (res: WebViewNavigationEvent) {
|
|
155
|
-
const result = {
|
|
156
|
-
type: 'load',
|
|
157
|
-
timeStamp: res.timeStamp,
|
|
158
|
-
detail: {
|
|
159
|
-
src: res.nativeEvent?.url
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
bindload?.(result)
|
|
163
|
-
}
|
|
164
|
-
const _error = function (res: WebViewErrorEvent) {
|
|
165
|
-
setPageLoadErr(true)
|
|
166
|
-
const result = {
|
|
167
|
-
type: 'error',
|
|
168
|
-
timeStamp: res.timeStamp,
|
|
169
|
-
detail: {
|
|
170
|
-
src: ''
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
binderror && binderror(result)
|
|
174
|
-
}
|
|
175
|
-
|
|
176
155
|
const _reload = function () {
|
|
177
156
|
setPageLoadErr(false)
|
|
178
157
|
}
|
|
@@ -307,17 +286,51 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((pr
|
|
|
307
286
|
}
|
|
308
287
|
})
|
|
309
288
|
}
|
|
310
|
-
const events = {}
|
|
311
289
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
290
|
+
let isLoadError = false
|
|
291
|
+
let fristLoaded = false
|
|
292
|
+
let statusCode: string | number = ''
|
|
293
|
+
const onLoadEnd = function (res: WebViewEvent) {
|
|
294
|
+
fristLoaded = true
|
|
295
|
+
isLoaded.current = true
|
|
296
|
+
const src = res.nativeEvent?.url
|
|
297
|
+
if (isLoadError) {
|
|
298
|
+
isLoadError = false
|
|
299
|
+
isNavigateBack.current = false
|
|
300
|
+
const result = {
|
|
301
|
+
type: 'error',
|
|
302
|
+
timeStamp: res.timeStamp,
|
|
303
|
+
detail: {
|
|
304
|
+
src,
|
|
305
|
+
statusCode
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
binderror && binderror(result)
|
|
309
|
+
} else {
|
|
310
|
+
const result = {
|
|
311
|
+
type: 'load',
|
|
312
|
+
timeStamp: res.timeStamp,
|
|
313
|
+
detail: {
|
|
314
|
+
src
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
bindload?.(result)
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
const onHttpError = function (res: WebViewHttpErrorEvent) {
|
|
321
|
+
isLoadError = true
|
|
322
|
+
statusCode = res.nativeEvent?.statusCode
|
|
323
|
+
}
|
|
324
|
+
const onError = function () {
|
|
325
|
+
statusCode = ''
|
|
326
|
+
isLoadError = true
|
|
327
|
+
if (!fristLoaded) {
|
|
328
|
+
setPageLoadErr(true)
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
const onLoadStart = function () {
|
|
332
|
+
isLoaded.current = false
|
|
316
333
|
}
|
|
317
|
-
|
|
318
|
-
extendObject(events, {
|
|
319
|
-
onError: _error
|
|
320
|
-
})
|
|
321
334
|
|
|
322
335
|
return (
|
|
323
336
|
<Portal key={pageLoadErr ? 'error' : 'webview'}>
|
|
@@ -329,17 +342,21 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((pr
|
|
|
329
342
|
</View>
|
|
330
343
|
)
|
|
331
344
|
: (<WebView
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
345
|
+
style={ defaultWebViewStyle }
|
|
346
|
+
source={{ uri: src }}
|
|
347
|
+
pointerEvents={ isLoaded ? 'auto' : 'none' }
|
|
348
|
+
ref={webViewRef}
|
|
349
|
+
javaScriptEnabled={true}
|
|
350
|
+
onNavigationStateChange={_changeUrl}
|
|
351
|
+
onMessage={_message}
|
|
352
|
+
injectedJavaScript={injectedJavaScript}
|
|
353
|
+
onLoadProgress={_onLoadProgress}
|
|
354
|
+
onLoadEnd={onLoadEnd}
|
|
355
|
+
onHttpError={onHttpError}
|
|
356
|
+
onError={onError}
|
|
357
|
+
onLoadStart={onLoadStart}
|
|
358
|
+
allowsBackForwardNavigationGestures={true}
|
|
359
|
+
></WebView>)}
|
|
343
360
|
</Portal>
|
|
344
361
|
)
|
|
345
362
|
})
|