@mpxjs/webpack-plugin 2.9.65 → 2.9.66
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 +5 -1
- package/lib/platform/style/wx/index.js +17 -46
- package/lib/react/processTemplate.js +4 -2
- package/lib/runtime/components/react/context.ts +8 -0
- package/lib/runtime/components/react/dist/context.js +1 -0
- package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +10 -2
- package/lib/runtime/components/react/dist/mpx-swiper/carouse.jsx +76 -76
- package/lib/runtime/components/react/dist/mpx-view.jsx +30 -11
- package/lib/runtime/components/react/dist/mpx-web-view.jsx +1 -1
- package/lib/runtime/components/react/dist/useAnimationHooks.js +215 -0
- package/lib/runtime/components/react/dist/utils.jsx +2 -1
- package/lib/runtime/components/react/mpx-scroll-view.tsx +11 -1
- package/lib/runtime/components/react/mpx-swiper/carouse.tsx +75 -74
- package/lib/runtime/components/react/mpx-view.tsx +39 -19
- package/lib/runtime/components/react/mpx-web-view.tsx +1 -1
- package/lib/runtime/components/react/types/common.ts +8 -2
- package/lib/runtime/components/react/useAnimationHooks.ts +248 -0
- package/lib/runtime/components/react/utils.tsx +6 -4
- package/lib/template-compiler/compiler.js +22 -17
- package/package.json +4 -3
package/lib/index.js
CHANGED
|
@@ -139,6 +139,7 @@ class MpxWebpackPlugin {
|
|
|
139
139
|
options.writeMode = options.writeMode || 'changed'
|
|
140
140
|
options.autoScopeRules = options.autoScopeRules || {}
|
|
141
141
|
options.autoVirtualHostRules = options.autoVirtualHostRules || {}
|
|
142
|
+
options.customTextRules = options.customTextRules || {}
|
|
142
143
|
options.forceDisableProxyCtor = options.forceDisableProxyCtor || false
|
|
143
144
|
options.transMpxRules = options.transMpxRules || {
|
|
144
145
|
include: () => true
|
|
@@ -173,6 +174,7 @@ class MpxWebpackPlugin {
|
|
|
173
174
|
options.subpackageModulesRules = options.subpackageModulesRules || {}
|
|
174
175
|
options.forceMainPackageRules = options.forceMainPackageRules || {}
|
|
175
176
|
options.forceProxyEventRules = options.forceProxyEventRules || {}
|
|
177
|
+
options.disableRequireAsync = options.disableRequireAsync || false
|
|
176
178
|
options.miniNpmPackages = options.miniNpmPackages || []
|
|
177
179
|
options.fileConditionRules = options.fileConditionRules || {
|
|
178
180
|
include: () => true
|
|
@@ -687,6 +689,7 @@ class MpxWebpackPlugin {
|
|
|
687
689
|
projectName: this.options.projectName,
|
|
688
690
|
autoScopeRules: this.options.autoScopeRules,
|
|
689
691
|
autoVirtualHostRules: this.options.autoVirtualHostRules,
|
|
692
|
+
customTextRules: this.options.customTextRules,
|
|
690
693
|
transRpxRules: this.options.transRpxRules,
|
|
691
694
|
postcssInlineConfig: this.options.postcssInlineConfig,
|
|
692
695
|
decodeHTMLText: this.options.decodeHTMLText,
|
|
@@ -708,7 +711,8 @@ class MpxWebpackPlugin {
|
|
|
708
711
|
useRelativePath: this.options.useRelativePath,
|
|
709
712
|
removedChunks: [],
|
|
710
713
|
forceProxyEventRules: this.options.forceProxyEventRules,
|
|
711
|
-
|
|
714
|
+
// 若配置disableRequireAsync=true, 则全平台构建不支持异步分包
|
|
715
|
+
supportRequireAsync: !this.options.disableRequireAsync && (this.options.mode === 'wx' || this.options.mode === 'ali' || this.options.mode === 'tt' || isWeb(this.options.mode)),
|
|
712
716
|
partialCompileRules: this.options.partialCompileRules,
|
|
713
717
|
collectDynamicEntryInfo: ({ resource, packageName, filename, entryType, hasAsync }) => {
|
|
714
718
|
const curInfo = mpx.dynamicEntryInfo[packageName] = mpx.dynamicEntryInfo[packageName] || {
|
|
@@ -190,12 +190,16 @@ module.exports = function getSpec ({ warn, error }) {
|
|
|
190
190
|
flex: ['flexGrow', 'flexShrink', 'flexBasis'],
|
|
191
191
|
// flex-flow: <'flex-direction'> or flex-flow: <'flex-direction'> and <'flex-wrap'>
|
|
192
192
|
'flex-flow': ['flexDirection', 'flexWrap'],
|
|
193
|
-
'border-radius': ['borderTopLeftRadius', 'borderTopRightRadius', 'borderBottomRightRadius', 'borderBottomLeftRadius']
|
|
193
|
+
'border-radius': ['borderTopLeftRadius', 'borderTopRightRadius', 'borderBottomRightRadius', 'borderBottomLeftRadius'],
|
|
194
|
+
'border-width': ['borderTopWidth', 'borderRightWidth', 'borderBottomWidth', 'borderLeftWidth'],
|
|
195
|
+
'border-color': ['borderTopColor', 'borderRightColor', 'borderBottomColor', 'borderLeftColor'],
|
|
196
|
+
margin: ['marginTop', 'marginRight', 'marginBottom', 'marginLeft'],
|
|
197
|
+
padding: ['paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft']
|
|
194
198
|
}
|
|
195
199
|
const formatAbbreviation = ({ prop, value, selector }, { mode }) => {
|
|
196
200
|
const original = `${prop}:${value}`
|
|
197
201
|
const props = AbbreviationMap[prop]
|
|
198
|
-
const values = parseValues(value)
|
|
202
|
+
const values = Array.isArray(value) ? value : parseValues(value)
|
|
199
203
|
const cssMap = []
|
|
200
204
|
let idx = 0
|
|
201
205
|
let propsIdx = 0
|
|
@@ -255,32 +259,20 @@ module.exports = function getSpec ({ warn, error }) {
|
|
|
255
259
|
return cssMap
|
|
256
260
|
}
|
|
257
261
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
const values = parseValues(value)
|
|
261
|
-
// format
|
|
262
|
-
let suffix = []
|
|
262
|
+
const formatCompositeVal = ({ prop, value, selector }, { mode }) => {
|
|
263
|
+
const values = parseValues(value).splice(0, 4)
|
|
263
264
|
switch (values.length) {
|
|
264
|
-
|
|
265
|
+
case 1:
|
|
266
|
+
verifyValues({ prop, value, selector }, false)
|
|
267
|
+
return { prop, value }
|
|
265
268
|
case 2:
|
|
266
|
-
|
|
269
|
+
values.push(...values)
|
|
267
270
|
break
|
|
268
271
|
case 3:
|
|
269
|
-
|
|
270
|
-
break
|
|
271
|
-
case 4:
|
|
272
|
-
suffix = ['Top', 'Right', 'Bottom', 'Left']
|
|
272
|
+
values.push(values[1])
|
|
273
273
|
break
|
|
274
274
|
}
|
|
275
|
-
return
|
|
276
|
-
const newProp = `${prop}${suffix[index] || ''}`
|
|
277
|
-
// validate
|
|
278
|
-
verifyValues({ prop: hump2dash(newProp), value, selector }, false)
|
|
279
|
-
return {
|
|
280
|
-
prop: newProp,
|
|
281
|
-
value: value
|
|
282
|
-
}
|
|
283
|
-
})
|
|
275
|
+
return formatAbbreviation({ prop, value: values, selector }, { mode })
|
|
284
276
|
}
|
|
285
277
|
|
|
286
278
|
// line-height
|
|
@@ -374,22 +366,6 @@ module.exports = function getSpec ({ warn, error }) {
|
|
|
374
366
|
return false
|
|
375
367
|
}
|
|
376
368
|
|
|
377
|
-
// border-radius 缩写转换
|
|
378
|
-
const getBorderRadius = ({ prop, value, selector }, { mode }) => {
|
|
379
|
-
const values = parseValues(value)
|
|
380
|
-
if (values.length === 1) {
|
|
381
|
-
verifyValues({ prop, value, selector }, false)
|
|
382
|
-
return { prop, value }
|
|
383
|
-
} else {
|
|
384
|
-
if (values.length === 2) {
|
|
385
|
-
values.push(...values)
|
|
386
|
-
} else if (values.length === 3) {
|
|
387
|
-
values.push(values[1])
|
|
388
|
-
}
|
|
389
|
-
return formatAbbreviation({ prop, value: values.join(' ') }, { mode })
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
|
|
393
369
|
// transform 转换
|
|
394
370
|
const formatTransform = ({ prop, value, selector }, { mode }) => {
|
|
395
371
|
if (Array.isArray(value)) return { prop, value }
|
|
@@ -566,15 +542,10 @@ module.exports = function getSpec ({ warn, error }) {
|
|
|
566
542
|
ios: checkBackgroundImage,
|
|
567
543
|
android: checkBackgroundImage
|
|
568
544
|
},
|
|
569
|
-
{
|
|
570
|
-
test: 'border-radius',
|
|
571
|
-
ios: getBorderRadius,
|
|
572
|
-
android: getBorderRadius
|
|
573
|
-
},
|
|
574
545
|
{ // margin padding 内外边距的处理
|
|
575
|
-
test: /^(margin|padding)$/,
|
|
576
|
-
ios:
|
|
577
|
-
android:
|
|
546
|
+
test: /^(margin|padding|border-radius|border-width|border-color)$/,
|
|
547
|
+
ios: formatCompositeVal,
|
|
548
|
+
android: formatCompositeVal
|
|
578
549
|
},
|
|
579
550
|
{ // line-height 换算
|
|
580
551
|
test: 'line-height',
|
|
@@ -27,7 +27,8 @@ module.exports = function (template, {
|
|
|
27
27
|
decodeHTMLText,
|
|
28
28
|
externalClasses,
|
|
29
29
|
checkUsingComponents,
|
|
30
|
-
autoVirtualHostRules
|
|
30
|
+
autoVirtualHostRules,
|
|
31
|
+
customTextRules
|
|
31
32
|
} = mpx
|
|
32
33
|
const { resourcePath } = parseRequest(loaderContext.resource)
|
|
33
34
|
const builtInComponentsMap = {}
|
|
@@ -84,7 +85,8 @@ module.exports = function (template, {
|
|
|
84
85
|
globalComponents: [],
|
|
85
86
|
// web模式下实现抽象组件
|
|
86
87
|
componentGenerics,
|
|
87
|
-
hasVirtualHost: matchCondition(resourcePath, autoVirtualHostRules)
|
|
88
|
+
hasVirtualHost: matchCondition(resourcePath, autoVirtualHostRules),
|
|
89
|
+
isCustomText: matchCondition(resourcePath, customTextRules)
|
|
88
90
|
})
|
|
89
91
|
|
|
90
92
|
if (meta.wxsContentMap) {
|
|
@@ -25,6 +25,12 @@ export interface FormContextValue {
|
|
|
25
25
|
reset: () => void
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
export interface IntersectionObserver {
|
|
29
|
+
[key: number]: {
|
|
30
|
+
throttleMeasure: () => void
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
28
34
|
export const MovableAreaContext = createContext({ width: 0, height: 0 })
|
|
29
35
|
|
|
30
36
|
export const FormContext = createContext<FormContextValue | null>(null)
|
|
@@ -38,3 +44,5 @@ export const LabelContext = createContext<LabelContextValue | null>(null)
|
|
|
38
44
|
export const PickerContext = createContext(null)
|
|
39
45
|
|
|
40
46
|
export const VarContext = createContext({})
|
|
47
|
+
|
|
48
|
+
export const IntersectionObserverContext = createContext<IntersectionObserver | null>(null)
|
|
@@ -33,15 +33,16 @@
|
|
|
33
33
|
*/
|
|
34
34
|
import { ScrollView } from 'react-native-gesture-handler';
|
|
35
35
|
import { RefreshControl } from 'react-native';
|
|
36
|
-
import { useRef, useState, useEffect, forwardRef } from 'react';
|
|
36
|
+
import { useRef, useState, useEffect, forwardRef, useContext } from 'react';
|
|
37
37
|
import { useAnimatedRef } from 'react-native-reanimated';
|
|
38
38
|
import { warn } from '@mpxjs/utils';
|
|
39
39
|
import useInnerProps, { getCustomEvent } from './getInnerListeners';
|
|
40
40
|
import useNodesRef from './useNodesRef';
|
|
41
41
|
import { splitProps, splitStyle, useTransformStyle, useLayout, wrapChildren } from './utils';
|
|
42
|
+
import { IntersectionObserverContext } from './context';
|
|
42
43
|
const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
|
|
43
44
|
const { textProps, innerProps: props = {} } = splitProps(scrollViewProps);
|
|
44
|
-
const { enhanced = false, bounces = true, style = {}, 'scroll-x': scrollX = false, 'scroll-y': scrollY = false, 'enable-back-to-top': enableBackToTop = false, 'paging-enabled': pagingEnabled = false, 'upper-threshold': upperThreshold = 50, 'lower-threshold': lowerThreshold = 50, 'scroll-with-animation': scrollWithAnimation, 'refresher-enabled': refresherEnabled, 'refresher-default-style': refresherDefaultStyle, 'refresher-background': refresherBackground, 'show-scrollbar': showScrollbar = true, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight } = props;
|
|
45
|
+
const { enhanced = false, bounces = true, style = {}, 'scroll-x': scrollX = false, 'scroll-y': scrollY = false, 'enable-back-to-top': enableBackToTop = false, 'enable-trigger-intersection-observer': enableTriggerIntersectionObserver = false, 'paging-enabled': pagingEnabled = false, 'upper-threshold': upperThreshold = 50, 'lower-threshold': lowerThreshold = 50, 'scroll-with-animation': scrollWithAnimation, 'refresher-enabled': refresherEnabled, 'refresher-default-style': refresherDefaultStyle, 'refresher-background': refresherBackground, 'show-scrollbar': showScrollbar = true, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight } = props;
|
|
45
46
|
const [refreshing, setRefreshing] = useState(true);
|
|
46
47
|
const snapScrollTop = useRef(0);
|
|
47
48
|
const snapScrollLeft = useRef(0);
|
|
@@ -56,6 +57,7 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
|
|
|
56
57
|
const hasCallScrollToUpper = useRef(true);
|
|
57
58
|
const hasCallScrollToLower = useRef(false);
|
|
58
59
|
const initialTimeout = useRef(null);
|
|
60
|
+
const intersectionObservers = useContext(IntersectionObserverContext);
|
|
59
61
|
const { normalStyle, hasVarDec, varContextRef, hasSelfPercent, setWidth, setHeight } = useTransformStyle(style, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
|
|
60
62
|
const { textStyle, innerStyle } = splitStyle(normalStyle);
|
|
61
63
|
const scrollViewRef = useAnimatedRef();
|
|
@@ -173,6 +175,11 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
|
|
|
173
175
|
layoutRef
|
|
174
176
|
}, props));
|
|
175
177
|
updateScrollOptions(e, { scrollLeft, scrollTop });
|
|
178
|
+
if (enableTriggerIntersectionObserver && intersectionObservers) {
|
|
179
|
+
for (const key in intersectionObservers) {
|
|
180
|
+
intersectionObservers[key].throttleMeasure();
|
|
181
|
+
}
|
|
182
|
+
}
|
|
176
183
|
}
|
|
177
184
|
function onScrollEnd(e) {
|
|
178
185
|
const { bindscrollend } = props;
|
|
@@ -279,6 +286,7 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
|
|
|
279
286
|
'scroll-x',
|
|
280
287
|
'scroll-y',
|
|
281
288
|
'enable-back-to-top',
|
|
289
|
+
'enable-trigger-intersection-observer',
|
|
282
290
|
'paging-enabled',
|
|
283
291
|
'show-scrollbar',
|
|
284
292
|
'upper-threshold',
|
|
@@ -67,6 +67,8 @@ const _Carouse = forwardRef((props, ref) => {
|
|
|
67
67
|
const initOffsetIndex = initIndex + (props.circular && totalElements > 1 ? 1 : 0);
|
|
68
68
|
const defaultX = (defaultWidth * initOffsetIndex) || 0;
|
|
69
69
|
const defaultY = (defaultHeight * initOffsetIndex) || 0;
|
|
70
|
+
// 主动scorllTo时是否要出发onScrollEnd
|
|
71
|
+
const needTriggerScrollEnd = useRef(true);
|
|
70
72
|
// 内部存储上一次的offset值
|
|
71
73
|
const autoplayTimerRef = useRef(null);
|
|
72
74
|
const scrollViewRef = useRef(null);
|
|
@@ -77,22 +79,21 @@ const _Carouse = forwardRef((props, ref) => {
|
|
|
77
79
|
// 内部存储上一次的偏移量
|
|
78
80
|
const internalsRef = useRef({
|
|
79
81
|
offset: {
|
|
80
|
-
x:
|
|
81
|
-
y:
|
|
82
|
+
x: 0,
|
|
83
|
+
y: 0
|
|
82
84
|
},
|
|
83
85
|
isScrolling: false
|
|
84
86
|
});
|
|
85
87
|
const isDragRef = useRef(false);
|
|
86
88
|
const [state, setState] = useState({
|
|
87
|
-
children: newChild,
|
|
88
89
|
width: dir === 'x' && typeof defaultWidth === 'number' ? defaultWidth - previousMargin - nextMargin : defaultWidth,
|
|
89
90
|
height: dir === 'y' && typeof defaultHeight === 'number' ? defaultHeight - previousMargin - nextMargin : defaultHeight,
|
|
90
91
|
// 真正的游标索引, 从0开始
|
|
91
92
|
index: initIndex,
|
|
92
93
|
total: totalElements,
|
|
93
94
|
offset: {
|
|
94
|
-
x:
|
|
95
|
-
y:
|
|
95
|
+
x: 0,
|
|
96
|
+
y: 0
|
|
96
97
|
},
|
|
97
98
|
dir
|
|
98
99
|
});
|
|
@@ -113,25 +114,38 @@ const _Carouse = forwardRef((props, ref) => {
|
|
|
113
114
|
}, [props.autoplay, props.current, state.index, state.width, state.height]);
|
|
114
115
|
useEffect(() => {
|
|
115
116
|
// 确认这个是变化的props变化的时候才执行,还是初始化的时候就执行
|
|
116
|
-
if (!props.autoplay && props.current !== state.index) {
|
|
117
|
+
if (!props.autoplay && props.current !== undefined && props.current !== state.index) {
|
|
117
118
|
const initIndex = props.current || 0;
|
|
118
119
|
// 这里要排除超过元素个数的设置
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
120
|
+
const { nextIndex, nextOffset } = getMultiNextConfig(props.current);
|
|
121
|
+
// 1. 安卓需要主动更新下内部状态, 2. IOS不能触发完wcrollTo之后立即updateState, 会造成滑动两次
|
|
122
|
+
// 2. setTimeout 是fix 当再渲染过程中触发scrollTo失败的问题
|
|
123
|
+
if (Platform.OS === 'ios') {
|
|
124
|
+
needTriggerScrollEnd.current = false;
|
|
125
|
+
setTimeout(() => {
|
|
126
|
+
scrollViewRef.current?.scrollTo({
|
|
127
|
+
...nextOffset,
|
|
128
|
+
animated: true
|
|
129
|
+
});
|
|
130
|
+
}, 50);
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
updateState(nextIndex, nextOffset);
|
|
134
|
+
}
|
|
133
135
|
}
|
|
134
|
-
}, [props.current]);
|
|
136
|
+
}, [props.current, state.width, state.height]);
|
|
137
|
+
function getMultiNextConfig(target) {
|
|
138
|
+
const step = state.dir === 'x' ? state.width : state.height;
|
|
139
|
+
const targetPos = step * props.current;
|
|
140
|
+
const targetOffset = {
|
|
141
|
+
x: dir === 'x' ? targetPos : 0,
|
|
142
|
+
y: dir === 'y' ? targetPos : 0
|
|
143
|
+
};
|
|
144
|
+
return {
|
|
145
|
+
nextIndex: target,
|
|
146
|
+
nextOffset: targetOffset
|
|
147
|
+
};
|
|
148
|
+
}
|
|
135
149
|
/**
|
|
136
150
|
* @desc: 更新状态: index和offset, 并响应索引变化的事件
|
|
137
151
|
* scrollViewOffset: 移动到的目标位置
|
|
@@ -181,7 +195,6 @@ const _Carouse = forwardRef((props, ref) => {
|
|
|
181
195
|
nextIndex = isBack ? nextIndex - 2 : nextIndex;
|
|
182
196
|
}
|
|
183
197
|
if (!props.circular) {
|
|
184
|
-
// nextIndex = isBack ? nextIndex - 2 : nextIndex
|
|
185
198
|
nextOffset = Object.assign({}, currentOffset, { [state.dir]: step * nextIndex });
|
|
186
199
|
}
|
|
187
200
|
else {
|
|
@@ -230,13 +243,12 @@ const _Carouse = forwardRef((props, ref) => {
|
|
|
230
243
|
createAutoPlay();
|
|
231
244
|
return;
|
|
232
245
|
}
|
|
233
|
-
if (!Array.isArray(
|
|
246
|
+
if (!Array.isArray(props.children)) {
|
|
234
247
|
return;
|
|
235
248
|
}
|
|
236
249
|
const step = state.dir === 'x' ? state.width : state.height;
|
|
237
250
|
const { nextOffset, autoMoveOffset, isAutoEnd } = getNextConfig(state.offset);
|
|
238
251
|
// 这里可以scroll到下一个元素, 但是把scrollView的偏移量在设置为content,视觉效果就没了吧
|
|
239
|
-
// scrollViewRef.current?.scrollTo({ x: nextOffset['x'], y: nextOffset['y'], animated: true })
|
|
240
252
|
if (Platform.OS === 'ios') {
|
|
241
253
|
if (!isAutoEnd) {
|
|
242
254
|
scrollViewRef.current?.scrollTo({ x: nextOffset.x, y: nextOffset.y, animated: true });
|
|
@@ -266,7 +278,6 @@ const _Carouse = forwardRef((props, ref) => {
|
|
|
266
278
|
// 安卓无法实现视觉的无缝连接, 只能回到真正的位置, 且安卓调用scrollTo不能触发onMomentumScrollEnd,还未找到为啥
|
|
267
279
|
if (state.dir === 'x') {
|
|
268
280
|
scrollViewRef.current?.scrollTo({ x: step, y: step, animated: true });
|
|
269
|
-
// scrollViewRef.current?.scrollTo({ x: autoMoveOffset.x, y: autoMoveOffset.y, animated: true })
|
|
270
281
|
}
|
|
271
282
|
else {
|
|
272
283
|
scrollViewRef.current?.scrollTo({ x: autoMoveOffset.x, y: step, animated: true });
|
|
@@ -283,9 +294,15 @@ const _Carouse = forwardRef((props, ref) => {
|
|
|
283
294
|
}
|
|
284
295
|
/**
|
|
285
296
|
* 当用户开始拖动结束
|
|
297
|
+
* 注意: 当手动调用scrollTo的时候, 安卓不会触发onMomentumScrollEnd, IOS会触发onMomentumScrollEnd
|
|
286
298
|
*/
|
|
287
299
|
function onScrollEnd(event) {
|
|
288
|
-
|
|
300
|
+
if (Platform.OS === 'ios' && !needTriggerScrollEnd.current) {
|
|
301
|
+
const { nextIndex, nextOffset } = getMultiNextConfig(props.current);
|
|
302
|
+
updateState(nextIndex, nextOffset);
|
|
303
|
+
needTriggerScrollEnd.current = true;
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
289
306
|
if (totalElements === 1) {
|
|
290
307
|
return;
|
|
291
308
|
}
|
|
@@ -311,58 +328,41 @@ const _Carouse = forwardRef((props, ref) => {
|
|
|
311
328
|
* @desc: 水平方向时,获取元素的布局,更新, 其中如果传递100%时需要依赖measure计算元算的宽高
|
|
312
329
|
*/
|
|
313
330
|
function onWrapperLayout(e) {
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
const
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
331
|
+
scrollViewRef.current?.measure((x, y, width, height, offsetLeft, offsetTop) => {
|
|
332
|
+
layoutRef.current = { x, y, width, height, offsetLeft, offsetTop };
|
|
333
|
+
const isWDiff = state.width !== width;
|
|
334
|
+
const isHDiff = state.height !== height;
|
|
335
|
+
if (isWDiff || isHDiff) {
|
|
336
|
+
const changeState = {
|
|
337
|
+
width: isWDiff ? width : state.width,
|
|
338
|
+
height: isHDiff ? height : state.height
|
|
339
|
+
};
|
|
340
|
+
const attr = state.dir === 'x' ? 'width' : 'height';
|
|
341
|
+
changeState[attr] = changeState[attr] - previousMargin - nextMargin;
|
|
342
|
+
const correctOffset = Object.assign({}, state.offset, {
|
|
343
|
+
[state.dir]: initOffsetIndex * (state.dir === 'x' ? changeState.width : changeState.height)
|
|
344
|
+
});
|
|
345
|
+
state.width = changeState.width;
|
|
346
|
+
state.height = changeState.height;
|
|
347
|
+
// 这里setState之后,会再触发重新渲染, renderScrollView会再次触发onScrollEnd,
|
|
348
|
+
setState((preState) => {
|
|
349
|
+
return {
|
|
350
|
+
...preState,
|
|
351
|
+
width: changeState.width,
|
|
352
|
+
height: changeState.height
|
|
328
353
|
};
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
});
|
|
334
|
-
state.offset = correctOffset;
|
|
335
|
-
state.width = changeState.width;
|
|
336
|
-
state.height = changeState.height;
|
|
337
|
-
setState((preState) => {
|
|
338
|
-
return {
|
|
339
|
-
...preState,
|
|
340
|
-
offset: correctOffset,
|
|
341
|
-
width: changeState.width,
|
|
342
|
-
height: changeState.height
|
|
343
|
-
};
|
|
344
|
-
});
|
|
345
|
-
scrollViewRef.current?.scrollTo({ x: correctOffset.x, y: correctOffset.y, animated: false });
|
|
346
|
-
}
|
|
347
|
-
props.getInnerLayout && props.getInnerLayout(layoutRef);
|
|
348
|
-
});
|
|
349
|
-
}
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
props.getInnerLayout && props.getInnerLayout(layoutRef);
|
|
357
|
+
});
|
|
350
358
|
}
|
|
351
359
|
function getOffset() {
|
|
352
360
|
const step = state.dir === 'x' ? state.width : state.height;
|
|
353
361
|
if (!step || Number.isNaN(+step))
|
|
354
362
|
return [];
|
|
355
363
|
const offsetArray = [];
|
|
356
|
-
|
|
357
|
-
offsetArray.push(
|
|
358
|
-
for (let i = 1; i < totalElements; i++) {
|
|
359
|
-
offsetArray.push(i * step - previousMargin);
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
else {
|
|
363
|
-
for (let i = 0; i < totalElements; i++) {
|
|
364
|
-
offsetArray.push(i * step);
|
|
365
|
-
}
|
|
364
|
+
for (let i = 0; i < totalElements; i++) {
|
|
365
|
+
offsetArray.push(i * step);
|
|
366
366
|
}
|
|
367
367
|
return offsetArray;
|
|
368
368
|
}
|
|
@@ -371,7 +371,7 @@ const _Carouse = forwardRef((props, ref) => {
|
|
|
371
371
|
const scrollElementProps = {
|
|
372
372
|
ref: scrollViewRef,
|
|
373
373
|
horizontal: props.horizontal,
|
|
374
|
-
pagingEnabled:
|
|
374
|
+
pagingEnabled: true,
|
|
375
375
|
snapToOffsets: offsetsArray,
|
|
376
376
|
decelerationRate: 0.99,
|
|
377
377
|
showsHorizontalScrollIndicator: false,
|
|
@@ -423,20 +423,21 @@ const _Carouse = forwardRef((props, ref) => {
|
|
|
423
423
|
</View>);
|
|
424
424
|
}
|
|
425
425
|
function renderPages() {
|
|
426
|
-
const { width, height
|
|
426
|
+
const { width, height } = state;
|
|
427
|
+
const { children } = props;
|
|
427
428
|
const { circular } = props;
|
|
428
429
|
const pageStyle = { width: width, height: height };
|
|
429
430
|
// 设置了previousMargin或者nextMargin,
|
|
430
431
|
// 1. 元素的宽度是减去这两个数目之和
|
|
431
432
|
// 2. previousMargin设置marginLeft正值, nextmargin设置marginRight负值
|
|
432
433
|
// 3. 第一个元素设置previousMargin 和 nextMargin, 最后一个元素
|
|
433
|
-
if (
|
|
434
|
+
if (totalElements > 1 && Array.isArray(children)) {
|
|
434
435
|
let arrElements = [];
|
|
435
436
|
// pages = ["2", "0", "1", "2", "0"]
|
|
436
437
|
const pages = Array.isArray(children) ? Object.keys(children) : [];
|
|
437
438
|
/* 无限循环的时候 */
|
|
438
439
|
if (circular) {
|
|
439
|
-
pages.unshift(
|
|
440
|
+
pages.unshift(totalElements - 1 + '');
|
|
440
441
|
pages.push('0');
|
|
441
442
|
}
|
|
442
443
|
arrElements = pages.map((page, i) => {
|
|
@@ -447,7 +448,6 @@ const _Carouse = forwardRef((props, ref) => {
|
|
|
447
448
|
else if (i === pages.length - 1 && typeof width === 'number') {
|
|
448
449
|
nextMargin && (extraStyle.marginRight = nextMargin);
|
|
449
450
|
}
|
|
450
|
-
// return (<View style={[pageStyle, styles.slide, extraStyle]} key={ 'page' + i}>{children[+page]}</View>)
|
|
451
451
|
return (<View style={[pageStyle, styles.slide, extraStyle]} key={'page' + i}>
|
|
452
452
|
{wrapChildren({
|
|
453
453
|
children: children[+page]
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
import { View, StyleSheet, Image } from 'react-native';
|
|
8
8
|
import { useRef, useState, useEffect, forwardRef } from 'react';
|
|
9
9
|
import useInnerProps from './getInnerListeners';
|
|
10
|
+
import Animated from 'react-native-reanimated';
|
|
11
|
+
import useAnimationHooks from './useAnimationHooks';
|
|
10
12
|
import useNodesRef from './useNodesRef';
|
|
11
13
|
import { parseUrl, PERCENT_REGEX, splitStyle, splitProps, useTransformStyle, wrapChildren, useLayout } from './utils';
|
|
12
14
|
import LinearGradient from 'react-native-linear-gradient';
|
|
@@ -527,7 +529,7 @@ function wrapWithChildren(props, { hasVarDec, enableBackground, textStyle, backg
|
|
|
527
529
|
}
|
|
528
530
|
const _View = forwardRef((viewProps, ref) => {
|
|
529
531
|
const { textProps, innerProps: props = {} } = splitProps(viewProps);
|
|
530
|
-
let { style = {}, 'hover-style': hoverStyle, 'hover-start-time': hoverStartTime = 50, 'hover-stay-time': hoverStayTime = 400, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'enable-background': enableBackground, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight } = props;
|
|
532
|
+
let { style = {}, 'hover-style': hoverStyle, 'hover-start-time': hoverStartTime = 50, 'hover-stay-time': hoverStayTime = 400, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'enable-background': enableBackground, 'enable-animation': enableAnimation, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, animation } = props;
|
|
531
533
|
const [isHover, setIsHover] = useState(false);
|
|
532
534
|
// 默认样式
|
|
533
535
|
const defaultStyle = {
|
|
@@ -592,9 +594,10 @@ const _View = forwardRef((viewProps, ref) => {
|
|
|
592
594
|
setStayTimer();
|
|
593
595
|
}
|
|
594
596
|
const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef });
|
|
597
|
+
const viewStyle = Object.assign({}, innerStyle, layoutStyle);
|
|
595
598
|
const innerProps = useInnerProps(props, {
|
|
596
599
|
ref: nodeRef,
|
|
597
|
-
style:
|
|
600
|
+
style: viewStyle,
|
|
598
601
|
...layoutProps,
|
|
599
602
|
...(hoverStyle && {
|
|
600
603
|
bindtouchstart: onTouchStart,
|
|
@@ -608,15 +611,31 @@ const _View = forwardRef((viewProps, ref) => {
|
|
|
608
611
|
], {
|
|
609
612
|
layoutRef
|
|
610
613
|
});
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
614
|
+
enableAnimation = enableAnimation || !!animation;
|
|
615
|
+
const enableAnimationRef = useRef(enableAnimation);
|
|
616
|
+
if (enableAnimationRef.current !== enableAnimation) {
|
|
617
|
+
throw new Error('[Mpx runtime error]: animation use should be stable in the component lifecycle, or you can set [enable-animation] with true.');
|
|
618
|
+
}
|
|
619
|
+
const finalStyle = enableAnimation
|
|
620
|
+
? useAnimationHooks({
|
|
621
|
+
animation,
|
|
622
|
+
style: viewStyle
|
|
623
|
+
})
|
|
624
|
+
: viewStyle;
|
|
625
|
+
const childNode = wrapWithChildren(props, {
|
|
626
|
+
hasVarDec,
|
|
627
|
+
enableBackground: enableBackgroundRef.current,
|
|
628
|
+
textStyle,
|
|
629
|
+
backgroundStyle,
|
|
630
|
+
varContext: varContextRef.current,
|
|
631
|
+
textProps
|
|
632
|
+
});
|
|
633
|
+
return animation?.actions?.length
|
|
634
|
+
? (<Animated.View {...innerProps} style={finalStyle}>
|
|
635
|
+
{childNode}
|
|
636
|
+
</Animated.View>)
|
|
637
|
+
: (<View {...innerProps}>
|
|
638
|
+
{childNode}
|
|
620
639
|
</View>);
|
|
621
640
|
});
|
|
622
641
|
_View.displayName = 'mpx-view';
|
|
@@ -6,7 +6,7 @@ import { promisify, redirectTo, navigateTo, navigateBack, reLaunch, switchTab }
|
|
|
6
6
|
import { WebView } from 'react-native-webview';
|
|
7
7
|
import useNodesRef from './useNodesRef';
|
|
8
8
|
const _WebView = forwardRef((props, ref) => {
|
|
9
|
-
const { src, bindmessage = noop, bindload = noop, binderror = noop } = props;
|
|
9
|
+
const { src = '', bindmessage = noop, bindload = noop, binderror = noop } = props;
|
|
10
10
|
if (props.style) {
|
|
11
11
|
warn('The web-view component does not support the style prop.');
|
|
12
12
|
}
|