@mpxjs/webpack-plugin 2.10.10 → 2.10.11-beta.2

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.
@@ -10,7 +10,6 @@ module.exports = function (content) {
10
10
  if (!mpx) {
11
11
  return content
12
12
  }
13
-
14
13
  const mode = mpx.mode
15
14
  const env = mpx.env
16
15
  const i18n = mpx.i18n
@@ -42,6 +42,7 @@ const wxs = require('./wxs')
42
42
  const component = require('./component')
43
43
  const fixComponentName = require('./fix-component-name')
44
44
  const rootPortal = require('./root-portal')
45
+ const pageContainer = require('./page-container')
45
46
  const stickyHeader = require('./sticky-header')
46
47
  const stickySection = require('./sticky-section')
47
48
 
@@ -128,6 +129,7 @@ module.exports = function getComponentConfigs ({ warn, error }) {
128
129
  label({ print }),
129
130
  component(),
130
131
  rootPortal({ print }),
132
+ pageContainer({ print }),
131
133
  stickyHeader({ print }),
132
134
  stickySection({ print })
133
135
  ]
@@ -0,0 +1,19 @@
1
+ const TAG_NAME = 'page-container'
2
+
3
+ module.exports = function ({ print }) {
4
+ return {
5
+ test: TAG_NAME,
6
+ ios (tag, { el }) {
7
+ el.isBuiltIn = true
8
+ return 'mpx-page-container'
9
+ },
10
+ android (tag, { el }) {
11
+ el.isBuiltIn = true
12
+ return 'mpx-page-container'
13
+ },
14
+ harmony (tag, { el }) {
15
+ el.isBuiltIn = true
16
+ return 'mpx-page-container'
17
+ }
18
+ }
19
+ }
@@ -11,7 +11,7 @@ const JD_UNSUPPORTED_TAG_NAME_ARR = ['functional-page-navigator', 'live-pusher',
11
11
  // 快应用不支持的标签集合
12
12
  const QA_UNSUPPORTED_TAG_NAME_ARR = ['movable-view', 'movable-area', 'open-data', 'official-account', 'editor', 'functional-page-navigator', 'live-player', 'live-pusher', 'ad', 'cover-image']
13
13
  // RN不支持的标签集合
14
- const RN_UNSUPPORTED_TAG_NAME_ARR = ['open-data', 'official-account', 'editor', 'functional-page-navigator', 'live-player', 'live-pusher', 'ad', 'progress', 'slider', 'audio', 'camera', 'match-media', 'page-container', 'editor', 'keyboard-accessory', 'map']
14
+ const RN_UNSUPPORTED_TAG_NAME_ARR = ['open-data', 'official-account', 'editor', 'functional-page-navigator', 'live-player', 'live-pusher', 'ad', 'progress', 'slider', 'audio', 'camera', 'match-media', 'editor', 'keyboard-accessory', 'map']
15
15
 
16
16
  /**
17
17
  * @param {function(object): function} print
@@ -0,0 +1,300 @@
1
+ import React, { createElement, forwardRef, useEffect, useRef, useState } from 'react';
2
+ import { StyleSheet, Dimensions, TouchableWithoutFeedback } from 'react-native';
3
+ import Animated, { useSharedValue, useAnimatedStyle, withTiming, cancelAnimation, runOnJS } from 'react-native-reanimated';
4
+ import { GestureDetector, Gesture } from 'react-native-gesture-handler';
5
+ import Portal from './mpx-portal/index';
6
+ import { usePreventRemove } from '@react-navigation/native';
7
+ import { extendObject, useLayout, useNavigation } from './utils';
8
+ import useInnerProps, { getCustomEvent } from './getInnerListeners';
9
+ import useNodesRef from './useNodesRef';
10
+ const screenWidth = Dimensions.get('screen').width;
11
+ function nextTick(cb) {
12
+ setTimeout(cb, 0);
13
+ }
14
+ function getInitialTranslate(position) {
15
+ switch (position) {
16
+ case 'top':
17
+ return -100;
18
+ case 'bottom':
19
+ return 100;
20
+ case 'right':
21
+ return 100;
22
+ case 'center':
23
+ return 0;
24
+ }
25
+ }
26
+ function getRoundStyle(position) {
27
+ switch (position) {
28
+ case 'top':
29
+ return {
30
+ borderBottomLeftRadius: 20,
31
+ borderBottomRightRadius: 20
32
+ };
33
+ case 'bottom':
34
+ return {
35
+ borderTopLeftRadius: 20,
36
+ borderTopRightRadius: 20
37
+ };
38
+ default: return {};
39
+ }
40
+ }
41
+ const PageContainer = forwardRef((props, ref) => {
42
+ const { show, duration = 300, 'z-index': zIndex = 100, overlay = true, position = 'bottom', round = false, 'close-on-slide-down': closeOnSlideDown = false, 'overlay-style': overlayStyle, 'custom-style': customStyle, bindclose, // RN下特有属性,用于同步show状态到父组件
43
+ bindbeforeenter, bindenter, bindafterenter, bindbeforeleave, bindleave, bindafterleave, bindclickoverlay, children } = props;
44
+ const isFirstRenderFlag = useRef(true);
45
+ const isFirstRender = isFirstRenderFlag.current;
46
+ if (isFirstRenderFlag.current) {
47
+ isFirstRenderFlag.current = false;
48
+ }
49
+ const triggerBeforeEnterEvent = () => bindbeforeenter?.(getCustomEvent('beforeenter', {}, {}, props));
50
+ const triggerEnterEvent = () => bindenter?.(getCustomEvent('enter', {}, {}, props));
51
+ const triggerAfterEnterEvent = () => bindafterenter?.(getCustomEvent('afterenter', {}, {}, props));
52
+ const triggerBeforeLeaveEvent = () => bindbeforeleave?.(getCustomEvent('beforeleave', {}, {}, props));
53
+ const triggerLeaveEvent = () => bindleave?.(getCustomEvent('leave', {}, {}, props));
54
+ const triggerAfterLeaveEvent = () => bindafterleave?.(getCustomEvent('afterleave', {}, {}, props));
55
+ const close = () => bindclose(getCustomEvent('close', {}, { detail: { value: false, source: 'close' } }, props));
56
+ // 控制组件是否挂载
57
+ const [internalVisible, setInternalVisible] = useState(show);
58
+ const overlayOpacity = useSharedValue(0);
59
+ const contentOpacity = useSharedValue(position === 'center' ? 0 : 1);
60
+ const contentTranslate = useSharedValue(getInitialTranslate(position));
61
+ const overlayAnimatedStyle = useAnimatedStyle(() => ({
62
+ opacity: overlayOpacity.value
63
+ }));
64
+ const sharedPosition = useSharedValue(position);
65
+ useEffect(() => {
66
+ sharedPosition.set(position);
67
+ }, [position]);
68
+ const contentAnimatedStyle = useAnimatedStyle(() => {
69
+ let transform = [];
70
+ if (sharedPosition.value === 'top' || sharedPosition.value === 'bottom') {
71
+ transform = [{ translateY: `${contentTranslate.value}%` }];
72
+ }
73
+ else if (sharedPosition.value === 'right') {
74
+ transform = [{ translateX: `${contentTranslate.value}%` }];
75
+ }
76
+ return {
77
+ opacity: contentOpacity.value,
78
+ transform
79
+ };
80
+ });
81
+ const currentTick = useRef(0);
82
+ function createTick() {
83
+ currentTick.current++;
84
+ const current = currentTick.current;
85
+ console.log('createTick ', current);
86
+ return () => {
87
+ console.log('isCurrentTick ', current, ', global tick is ' + currentTick.current);
88
+ return currentTick.current === current;
89
+ };
90
+ }
91
+ function clearAnimation() {
92
+ cancelAnimation(overlayOpacity);
93
+ cancelAnimation(contentOpacity);
94
+ cancelAnimation(contentTranslate);
95
+ }
96
+ // 播放入场动画
97
+ const animateIn = () => {
98
+ const isCurrentTick = createTick();
99
+ triggerBeforeEnterEvent();
100
+ nextTick(() => {
101
+ const animateOutFinish = internalVisible === false;
102
+ setInternalVisible(true);
103
+ triggerEnterEvent();
104
+ if (!isCurrentTick())
105
+ return;
106
+ const animateEnd = () => {
107
+ if (!isCurrentTick())
108
+ return;
109
+ triggerAfterEnterEvent();
110
+ };
111
+ /**
112
+ * 对齐 微信小程序
113
+ * 如果退场动画已经结束,则需将内容先移动到对应动画的初始位置
114
+ * 否则,结束退场动画,从当前位置作为初始位置完成进场动画,且退场动画时长将缩短
115
+ */
116
+ let durationTime = duration;
117
+ if (animateOutFinish) {
118
+ contentTranslate.set(getInitialTranslate(position));
119
+ contentOpacity.set(position === 'center' ? 0 : 1);
120
+ }
121
+ else {
122
+ clearAnimation();
123
+ if (position === 'center') {
124
+ durationTime = durationTime * (1 - contentOpacity.value);
125
+ }
126
+ else {
127
+ durationTime = durationTime * (contentTranslate.value / 100);
128
+ }
129
+ }
130
+ overlayOpacity.value = withTiming(1, { duration: durationTime });
131
+ if (position === 'center') {
132
+ contentOpacity.value = withTiming(1, { duration: durationTime }, () => {
133
+ runOnJS(animateEnd)();
134
+ });
135
+ contentTranslate.value = withTiming(0, { duration: durationTime });
136
+ }
137
+ else {
138
+ contentOpacity.value = withTiming(1, { duration: durationTime });
139
+ contentTranslate.value = withTiming(0, { duration: durationTime }, () => {
140
+ runOnJS(animateEnd)();
141
+ });
142
+ }
143
+ });
144
+ };
145
+ // 播放离场动画
146
+ const animateOut = () => {
147
+ const isCurrentTick = createTick();
148
+ triggerBeforeLeaveEvent();
149
+ nextTick(() => {
150
+ triggerLeaveEvent();
151
+ if (!isCurrentTick())
152
+ return;
153
+ const animateEnd = () => {
154
+ if (!isCurrentTick())
155
+ return; // 如果动画被cancelAnimation依然会触发回调,所以在此也需要判断Tick
156
+ triggerAfterLeaveEvent();
157
+ setInternalVisible(false);
158
+ };
159
+ if (position === 'center') {
160
+ contentOpacity.value = withTiming(0, { duration }, () => {
161
+ runOnJS(animateEnd)();
162
+ });
163
+ contentTranslate.value = withTiming(getInitialTranslate(position), { duration });
164
+ }
165
+ else {
166
+ contentOpacity.value = withTiming(0, { duration });
167
+ contentTranslate.value = withTiming(getInitialTranslate(position), { duration }, () => {
168
+ runOnJS(animateEnd)();
169
+ });
170
+ }
171
+ overlayOpacity.value = withTiming(0, { duration });
172
+ });
173
+ };
174
+ useEffect(() => {
175
+ // 如果展示状态和挂载状态一致,则不需要做任何操作
176
+ if (show) {
177
+ animateIn();
178
+ }
179
+ else {
180
+ if (!isFirstRender)
181
+ animateOut();
182
+ }
183
+ }, [show]);
184
+ const navigation = useNavigation();
185
+ usePreventRemove(show, (event) => {
186
+ const { data } = event;
187
+ if (show) {
188
+ close();
189
+ }
190
+ else {
191
+ navigation?.dispatch(data.action);
192
+ }
193
+ });
194
+ /**
195
+ * IOS 下需要关闭手势返回(原因: IOS手势返回时页面会跟随手指滑动,但是实际返回动作是在松手时触发,需禁掉页面跟随手指滑动的效果)
196
+ * 禁用与启用逻辑抽离为rnConfig由外部实现,并补充纯RN下默认实现
197
+ */
198
+ if (__mpx_mode__ === 'ios') {
199
+ // eslint-disable-next-line react-hooks/rules-of-hooks
200
+ useEffect(() => {
201
+ if (typeof global.__mpx.config?.rnConfig?.disableSwipeBack === 'function') {
202
+ global.__mpx.config.rnConfig.disableSwipeBack({ disable: show });
203
+ }
204
+ else {
205
+ navigation?.setOptions({
206
+ gestureEnabled: !show
207
+ });
208
+ }
209
+ }, [show]);
210
+ }
211
+ const THRESHOLD = screenWidth * 0.3; // 距离阈值
212
+ const VELOCITY_THRESHOLD = 1000; // px/s
213
+ const contentGesture = Gesture.Pan()
214
+ .activeOffsetY(150) // 下滑至少滑动 150px 才处理
215
+ .onEnd((e) => {
216
+ const { velocityY, translationY } = e;
217
+ const shouldGoBack = translationY > THRESHOLD || velocityY > VELOCITY_THRESHOLD;
218
+ if (shouldGoBack) {
219
+ runOnJS(close)();
220
+ }
221
+ });
222
+ /**
223
+ * 全屏幕 IOS 左滑手势返回(ios默认页面返回存在页面跟手逻辑,page-container暂不支持,对齐微信小程序)
224
+ * 1: 仅在屏幕左边缘滑动 才触发返回手势。
225
+ * 2: 用户滑动距离足够 或 滑动速度足够快,才触发返回。
226
+ * 3: 用户中途回退(滑回来)或滑太慢/太短,则应取消返回。
227
+ */
228
+ const screenGesture = Gesture.Pan()
229
+ .onEnd((e) => {
230
+ const { velocityX, translationX } = e;
231
+ const shouldGoBack = translationX > THRESHOLD || velocityX > VELOCITY_THRESHOLD;
232
+ if (shouldGoBack) {
233
+ runOnJS(close)();
234
+ }
235
+ })
236
+ .hitSlop({ left: 0, width: 30 }); // 从屏幕左侧 30px 内触发才处理
237
+ const renderMask = () => {
238
+ const onPress = () => {
239
+ close();
240
+ bindclickoverlay?.(getCustomEvent('clickoverlay', {}, { detail: { value: false, source: 'clickoverlay' } }, props));
241
+ };
242
+ return createElement(TouchableWithoutFeedback, { onPress }, createElement(Animated.View, { style: [styles.overlay, overlayStyle, overlayAnimatedStyle] }));
243
+ };
244
+ const renderContent = () => {
245
+ const contentView = (<Animated.View style={[
246
+ styles.container,
247
+ getRoundStyle(position),
248
+ positionStyle[position],
249
+ customStyle,
250
+ contentAnimatedStyle
251
+ ]}>
252
+ {children}
253
+ </Animated.View>);
254
+ return closeOnSlideDown
255
+ ? <GestureDetector gesture={contentGesture}>{contentView}</GestureDetector>
256
+ : contentView;
257
+ };
258
+ const nodeRef = useRef(null);
259
+ useNodesRef(props, ref, nodeRef, {});
260
+ const { layoutRef, layoutProps } = useLayout({ props, hasSelfPercent: false, nodeRef });
261
+ const innerProps = useInnerProps(extendObject({}, props, {
262
+ ref: nodeRef
263
+ }, layoutProps), [], { layoutRef });
264
+ const wrapperProps = extendObject(innerProps, {
265
+ style: [styles.wrapper, { zIndex }]
266
+ });
267
+ const renderWrapped = () => {
268
+ const wrappedView = (<Animated.View {...wrapperProps}>
269
+ {overlay ? renderMask() : null}
270
+ {renderContent()}
271
+ </Animated.View>);
272
+ return __mpx_mode__ === 'ios'
273
+ ? <GestureDetector gesture={screenGesture}>{wrappedView}</GestureDetector>
274
+ : wrappedView;
275
+ };
276
+ // TODO 是否有必要支持refs? dataset?
277
+ return createElement(Portal, null, internalVisible ? renderWrapped() : null);
278
+ });
279
+ const styles = StyleSheet.create({
280
+ wrapper: extendObject({
281
+ justifyContent: 'flex-end',
282
+ alignItems: 'center'
283
+ }, StyleSheet.absoluteFillObject),
284
+ overlay: extendObject({
285
+ backgroundColor: 'rgba(0,0,0,0.5)'
286
+ }, StyleSheet.absoluteFillObject),
287
+ container: {
288
+ position: 'absolute',
289
+ backgroundColor: 'white',
290
+ overflow: 'hidden'
291
+ }
292
+ });
293
+ const positionStyle = {
294
+ bottom: { bottom: 0, width: '100%', height: 'auto' },
295
+ top: { top: 0, width: '100%', height: 'auto' },
296
+ right: extendObject({}, StyleSheet.absoluteFillObject, { right: 0 }),
297
+ center: extendObject({}, StyleSheet.absoluteFillObject)
298
+ };
299
+ PageContainer.displayName = 'PageContainer';
300
+ export default PageContainer;
@@ -74,6 +74,7 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
74
74
  black: ['#000'],
75
75
  white: ['#fff']
76
76
  };
77
+ const isContentSizeChange = useRef(false);
77
78
  const { refresherContent, otherContent } = getRefresherContent(props.children);
78
79
  const hasRefresher = refresherContent && refresherEnabled;
79
80
  const { normalStyle, hasVarDec, varContextRef, hasSelfPercent, hasPositionFixed, setWidth, setHeight } = useTransformStyle(style, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
@@ -206,7 +207,22 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
206
207
  }
207
208
  }
208
209
  function onContentSizeChange(width, height) {
209
- scrollOptions.current.contentLength = selectLength({ height, width });
210
+ isContentSizeChange.current = true;
211
+ const newContentLength = selectLength({ height, width });
212
+ const oldContentLength = scrollOptions.current.contentLength;
213
+ scrollOptions.current.contentLength = newContentLength;
214
+ // 内容高度变化时,Animated.event 的映射可能会有不生效的场景,所以需要手动设置一下 scrollOffset 的值
215
+ if (enableSticky && (__mpx_mode__ === 'android' || __mpx_mode__ === 'ios')) {
216
+ // 当内容变少时,检查当前滚动位置是否超出新的内容范围
217
+ if (newContentLength < oldContentLength) {
218
+ const { visibleLength, offset } = scrollOptions.current;
219
+ const maxOffset = Math.max(0, newContentLength - visibleLength);
220
+ // 如果当前滚动位置超出了新的内容范围,调整滚动offset
221
+ if (offset > maxOffset && scrollY) {
222
+ scrollOffset.setValue(maxOffset);
223
+ }
224
+ }
225
+ }
210
226
  }
211
227
  function onLayout(e) {
212
228
  const layout = e.nativeEvent.layout || {};
@@ -226,8 +242,9 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
226
242
  }
227
243
  function onScroll(e) {
228
244
  const { bindscroll } = props;
229
- const { x: scrollLeft, y: scrollTop } = e.nativeEvent.contentOffset;
230
- const { width: scrollWidth, height: scrollHeight } = e.nativeEvent.contentSize;
245
+ const { contentOffset, layoutMeasurement, contentSize } = e.nativeEvent;
246
+ const { x: scrollLeft, y: scrollTop } = contentOffset;
247
+ const { width: scrollWidth, height: scrollHeight } = contentSize;
231
248
  isAtTop.value = scrollTop <= 0;
232
249
  bindscroll &&
233
250
  bindscroll(getCustomEvent('scroll', e, {
@@ -237,7 +254,8 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
237
254
  scrollHeight,
238
255
  scrollWidth,
239
256
  deltaX: scrollLeft - scrollOptions.current.scrollLeft,
240
- deltaY: scrollTop - scrollOptions.current.scrollTop
257
+ deltaY: scrollTop - scrollOptions.current.scrollTop,
258
+ layoutMeasurement
241
259
  },
242
260
  layoutRef
243
261
  }, props));
@@ -250,8 +268,9 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
250
268
  }
251
269
  function onScrollEnd(e) {
252
270
  const { bindscrollend } = props;
253
- const { x: scrollLeft, y: scrollTop } = e.nativeEvent.contentOffset;
254
- const { width: scrollWidth, height: scrollHeight } = e.nativeEvent.contentSize;
271
+ const { contentOffset, layoutMeasurement, contentSize } = e.nativeEvent;
272
+ const { x: scrollLeft, y: scrollTop } = contentOffset;
273
+ const { width: scrollWidth, height: scrollHeight } = contentSize;
255
274
  isAtTop.value = scrollTop <= 0;
256
275
  bindscrollend &&
257
276
  bindscrollend(getCustomEvent('scrollend', e, {
@@ -259,7 +278,8 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
259
278
  scrollLeft,
260
279
  scrollTop,
261
280
  scrollHeight,
262
- scrollWidth
281
+ scrollWidth,
282
+ layoutMeasurement
263
283
  },
264
284
  layoutRef
265
285
  }, props));
@@ -333,6 +353,16 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
333
353
  const scrollHandler = RNAnimated.event([{ nativeEvent: { contentOffset: { y: scrollOffset } } }], {
334
354
  useNativeDriver: true,
335
355
  listener: (event) => {
356
+ const y = event.nativeEvent.contentOffset.y || 0;
357
+ // 内容高度变化时,鸿蒙中 listener 回调通过scrollOffset.__getValue获取值一直等于event.nativeEvent.contentOffset.y,值是正确的,但是无法触发 sticky 动画执行,所以需要手动再 set 一次
358
+ if (__mpx_mode__ === 'harmony') {
359
+ if (isContentSizeChange.current) {
360
+ scrollOffset.setValue(y);
361
+ setTimeout(() => {
362
+ isContentSizeChange.current = false;
363
+ }, 100);
364
+ }
365
+ }
336
366
  onScroll(event);
337
367
  }
338
368
  });
@@ -495,6 +525,7 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
495
525
  showsVerticalScrollIndicator: scrollY && showScrollbar,
496
526
  scrollEnabled: !enableScroll ? false : !!(scrollX || scrollY),
497
527
  bounces: false,
528
+ overScrollMode: 'never',
498
529
  ref: scrollViewRef,
499
530
  onScroll: enableSticky ? scrollHandler : onScroll,
500
531
  onContentSizeChange: onContentSizeChange,
@@ -71,7 +71,7 @@ const easeMap = {
71
71
  easeInOutCubic: Easing.inOut(Easing.cubic)
72
72
  };
73
73
  const SwiperWrapper = forwardRef((props, ref) => {
74
- const { 'indicator-dots': showPagination, '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, 'simultaneous-handlers': originSimultaneousHandlers = [], 'wait-for': waitFor = [], style = {}, autoplay = false, circular = false, disableGesture = false } = props;
74
+ const { 'indicator-dots': showPagination, '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, 'simultaneous-handlers': originSimultaneousHandlers = [], 'wait-for': waitFor = [], style = {}, autoplay = false, circular = false, disableGesture = false, bindchange } = props;
75
75
  const easeingFunc = props['easing-function'] || 'default';
76
76
  const easeDuration = props.duration || 500;
77
77
  const horizontal = props.vertical !== undefined ? !props.vertical : true;
@@ -329,7 +329,7 @@ const SwiperWrapper = forwardRef((props, ref) => {
329
329
  function handleSwiperChange(current) {
330
330
  if (props.current !== currentIndex.value) {
331
331
  const eventData = getCustomEvent('change', {}, { detail: { current, source: 'touch' }, layoutRef: layoutRef });
332
- props.bindchange && props.bindchange(eventData);
332
+ bindchange && bindchange(eventData);
333
333
  }
334
334
  }
335
335
  function getOffset(index, stepValue) {
@@ -373,7 +373,7 @@ const SwiperWrapper = forwardRef((props, ref) => {
373
373
  // 1. 用户在当前页切换选中项,动画;用户携带选中index打开到swiper页直接选中不走动画
374
374
  useAnimatedReaction(() => currentIndex.value, (newIndex, preIndex) => {
375
375
  // 这里必须传递函数名, 直接写()=> {}形式会报 访问了未sharedValue信息
376
- if (newIndex !== preIndex && props.bindchange) {
376
+ if (newIndex !== preIndex && bindchange) {
377
377
  runOnJS(handleSwiperChange)(newIndex);
378
378
  }
379
379
  });