@mpxjs/webpack-plugin 2.10.12 → 2.10.13
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/dependencies/DynamicEntryDependency.js +9 -6
- package/lib/dependencies/ImportDependencyTemplate.js +12 -0
- package/lib/index.js +21 -2
- package/lib/react/LoadAsyncChunkModule.js +1 -1
- package/lib/react/processScript.js +5 -2
- package/lib/retry-runtime-module.js +56 -0
- package/lib/runtime/components/react/dist/mpx-async-suspense.jsx +13 -4
- package/lib/runtime/components/react/dist/mpx-swiper.jsx +151 -71
- package/lib/runtime/components/react/dist/useAnimationHooks.js +8 -1
- package/lib/runtime/components/react/dist/utils.jsx +17 -6
- package/lib/runtime/components/react/mpx-async-suspense.tsx +14 -4
- package/lib/runtime/components/react/mpx-swiper.tsx +155 -75
- package/lib/runtime/components/react/types/global.d.ts +2 -0
- package/lib/runtime/components/react/useAnimationHooks.ts +8 -1
- package/lib/runtime/components/react/utils.tsx +20 -6
- package/lib/web/processMainScript.js +1 -1
- package/lib/web/processScript.js +6 -2
- package/lib/web/script-helper.js +15 -10
- package/package.json +4 -4
|
@@ -6,6 +6,7 @@ const toPosix = require('../utils/to-posix')
|
|
|
6
6
|
const async = require('async')
|
|
7
7
|
const parseRequest = require('../utils/parse-request')
|
|
8
8
|
const hasOwn = require('../utils/has-own')
|
|
9
|
+
const { RetryRuntimeGlobal } = require('../retry-runtime-module')
|
|
9
10
|
|
|
10
11
|
class DynamicEntryDependency extends NullDependency {
|
|
11
12
|
constructor (range, request, entryType, outputPath = '', packageRoot = '', relativePath = '', context = '', extraOptions = {}) {
|
|
@@ -201,9 +202,11 @@ class DynamicEntryDependency extends NullDependency {
|
|
|
201
202
|
DynamicEntryDependency.Template = class DynamicEntryDependencyTemplate {
|
|
202
203
|
apply (dep, source, {
|
|
203
204
|
module,
|
|
204
|
-
chunkGraph
|
|
205
|
+
chunkGraph,
|
|
206
|
+
runtimeRequirements
|
|
205
207
|
}) {
|
|
206
|
-
const { resultPath,
|
|
208
|
+
const { resultPath, key, publicPath, extraOptions } = dep
|
|
209
|
+
let range = dep.range
|
|
207
210
|
|
|
208
211
|
let replaceContent = ''
|
|
209
212
|
|
|
@@ -214,10 +217,10 @@ DynamicEntryDependency.Template = class DynamicEntryDependencyTemplate {
|
|
|
214
217
|
let relativePath = toPosix(path.relative(publicPath + path.dirname(chunkGraph.getModuleChunks(module)[0].name), resultPath))
|
|
215
218
|
if (!relativePath.startsWith('.')) relativePath = './' + relativePath
|
|
216
219
|
replaceContent = JSON.stringify(relativePath)
|
|
217
|
-
if (extraOptions.retryRequireAsync) {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
}`
|
|
220
|
+
if (extraOptions.retryRequireAsync && extraOptions.retryRequireAsync.times > 0) {
|
|
221
|
+
range = extraOptions.requireAsyncRange
|
|
222
|
+
runtimeRequirements.add(RetryRuntimeGlobal)
|
|
223
|
+
replaceContent = `${RetryRuntimeGlobal}(function() { return require.async(${JSON.stringify(relativePath)}) }, ${extraOptions.retryRequireAsync.times}, ${extraOptions.retryRequireAsync.interval})`
|
|
221
224
|
}
|
|
222
225
|
} else {
|
|
223
226
|
replaceContent = JSON.stringify(resultPath)
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
const ModuleDependency = require('webpack/lib/dependencies/ModuleDependency')
|
|
2
|
+
const { RetryRuntimeGlobal } = require('../retry-runtime-module')
|
|
3
|
+
const parseRequest = require('../utils/parse-request')
|
|
2
4
|
|
|
3
5
|
class ImportDependencyTemplate extends (
|
|
4
6
|
ModuleDependency.Template
|
|
@@ -31,6 +33,16 @@ class ImportDependencyTemplate extends (
|
|
|
31
33
|
content = content.replace(/(__webpack_require__\.t\.bind\(.+,\s*)(\d+)(\s*\))/, (_, p1, p2, p3) => {
|
|
32
34
|
return p1 + '9' + p3
|
|
33
35
|
})
|
|
36
|
+
|
|
37
|
+
const { queryObj } = parseRequest(dep.request)
|
|
38
|
+
const retryRequireAsync = queryObj.retryRequireAsync && JSON.parse(queryObj.retryRequireAsync)
|
|
39
|
+
|
|
40
|
+
// require.async 的场景且配置了重试次数才注入 RetryRuntimeModule
|
|
41
|
+
if (queryObj.isRequireAsync && retryRequireAsync && retryRequireAsync.times > 0) {
|
|
42
|
+
runtimeRequirements.add(RetryRuntimeGlobal)
|
|
43
|
+
content = `${RetryRuntimeGlobal}(function() { return ${content} }, ${retryRequireAsync.times}, ${retryRequireAsync.interval})`
|
|
44
|
+
}
|
|
45
|
+
|
|
34
46
|
source.replace(dep.range[0], dep.range[1] - 1, content)
|
|
35
47
|
}
|
|
36
48
|
}
|
package/lib/index.js
CHANGED
|
@@ -77,6 +77,7 @@ const VirtualModulesPlugin = require('webpack-virtual-modules')
|
|
|
77
77
|
const RuntimeGlobals = require('webpack/lib/RuntimeGlobals')
|
|
78
78
|
const LoadAsyncChunkModule = require('./react/LoadAsyncChunkModule')
|
|
79
79
|
const ExternalModule = require('webpack/lib/ExternalModule')
|
|
80
|
+
const { RetryRuntimeModule, RetryRuntimeGlobal } = require('./retry-runtime-module')
|
|
80
81
|
require('./utils/check-core-version-match')
|
|
81
82
|
|
|
82
83
|
const isProductionLikeMode = options => {
|
|
@@ -202,6 +203,12 @@ class MpxWebpackPlugin {
|
|
|
202
203
|
options.asyncSubpackageRules = options.asyncSubpackageRules || []
|
|
203
204
|
options.optimizeRenderRules = options.optimizeRenderRules ? (Array.isArray(options.optimizeRenderRules) ? options.optimizeRenderRules : [options.optimizeRenderRules]) : []
|
|
204
205
|
options.retryRequireAsync = options.retryRequireAsync || false
|
|
206
|
+
if (options.retryRequireAsync === true) {
|
|
207
|
+
options.retryRequireAsync = {
|
|
208
|
+
times: 1,
|
|
209
|
+
interval: 0
|
|
210
|
+
}
|
|
211
|
+
}
|
|
205
212
|
options.optimizeSize = options.optimizeSize || false
|
|
206
213
|
options.dynamicComponentRules = options.dynamicComponentRules || {}// 运行时组件配置
|
|
207
214
|
this.options = options
|
|
@@ -615,6 +622,13 @@ class MpxWebpackPlugin {
|
|
|
615
622
|
}
|
|
616
623
|
})
|
|
617
624
|
|
|
625
|
+
compilation.hooks.runtimeRequirementInTree
|
|
626
|
+
.for(RetryRuntimeGlobal)
|
|
627
|
+
.tap('MpxWebpackPlugin', (chunk) => {
|
|
628
|
+
compilation.addRuntimeModule(chunk, new RetryRuntimeModule())
|
|
629
|
+
return true
|
|
630
|
+
})
|
|
631
|
+
|
|
618
632
|
if (isReact(this.options.mode)) {
|
|
619
633
|
compilation.hooks.runtimeRequirementInTree
|
|
620
634
|
.for(RuntimeGlobals.loadScript)
|
|
@@ -1436,6 +1450,10 @@ class MpxWebpackPlugin {
|
|
|
1436
1450
|
if (mpx.supportRequireAsync) {
|
|
1437
1451
|
if (isWeb(mpx.mode) || isReact(mpx.mode)) {
|
|
1438
1452
|
if (isReact(mpx.mode)) tarRoot = transSubpackage(mpx.transSubpackageRules, tarRoot)
|
|
1453
|
+
request = addQuery(request, {
|
|
1454
|
+
isRequireAsync: true,
|
|
1455
|
+
retryRequireAsync: JSON.stringify(this.options.retryRequireAsync)
|
|
1456
|
+
})
|
|
1439
1457
|
const depBlock = new AsyncDependenciesBlock(
|
|
1440
1458
|
{
|
|
1441
1459
|
name: tarRoot + '/index'
|
|
@@ -1451,7 +1469,8 @@ class MpxWebpackPlugin {
|
|
|
1451
1469
|
const dep = new DynamicEntryDependency(range, request, 'export', '', tarRoot, '', context, {
|
|
1452
1470
|
isAsync: true,
|
|
1453
1471
|
isRequireAsync: true,
|
|
1454
|
-
retryRequireAsync:
|
|
1472
|
+
retryRequireAsync: this.options.retryRequireAsync,
|
|
1473
|
+
requireAsyncRange: expr.range
|
|
1455
1474
|
})
|
|
1456
1475
|
|
|
1457
1476
|
parser.state.current.addPresentationalDependency(dep)
|
|
@@ -1606,7 +1625,7 @@ class MpxWebpackPlugin {
|
|
|
1606
1625
|
target = expr.object
|
|
1607
1626
|
}
|
|
1608
1627
|
|
|
1609
|
-
if (!matchCondition(resourcePath, this.options.transMpxRules) || resourcePath.indexOf('node_modules/@mpxjs') !== -1 || !target || mode === srcMode) return
|
|
1628
|
+
if (!matchCondition(resourcePath, this.options.transMpxRules) || toPosix(resourcePath).indexOf('node_modules/@mpxjs') !== -1 || !target || mode === srcMode) return
|
|
1610
1629
|
|
|
1611
1630
|
const type = target.name
|
|
1612
1631
|
const name = type === 'wx' ? 'mpx' : 'createFactory'
|
|
@@ -5,7 +5,7 @@ const HelperRuntimeModule = require('webpack/lib/runtime/HelperRuntimeModule')
|
|
|
5
5
|
class LoadAsyncChunkRuntimeModule extends HelperRuntimeModule {
|
|
6
6
|
constructor (timeout) {
|
|
7
7
|
super('load async chunk')
|
|
8
|
-
this.timeout = timeout ||
|
|
8
|
+
this.timeout = timeout || 10000
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
generate () {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const normalize = require('../utils/normalize')
|
|
2
2
|
const optionProcessorPath = normalize.lib('runtime/optionProcessorReact')
|
|
3
|
-
const { buildPagesMap, buildComponentsMap, getRequireScript, buildGlobalParams, stringifyRequest } = require('./script-helper')
|
|
3
|
+
const { buildPagesMap, buildComponentsMap, getRequireScript, buildGlobalParams, stringifyRequest, buildI18n } = require('./script-helper')
|
|
4
4
|
|
|
5
5
|
module.exports = function (script, {
|
|
6
6
|
loaderContext,
|
|
@@ -17,7 +17,7 @@ module.exports = function (script, {
|
|
|
17
17
|
componentGenerics,
|
|
18
18
|
genericsInfo
|
|
19
19
|
}, callback) {
|
|
20
|
-
const { appInfo } = loaderContext.getMpx()
|
|
20
|
+
const { appInfo, i18n } = loaderContext.getMpx()
|
|
21
21
|
|
|
22
22
|
let scriptSrcMode = srcMode
|
|
23
23
|
if (script) {
|
|
@@ -62,6 +62,9 @@ import { getComponent, getAsyncSuspense } from ${stringifyRequest(loaderContext,
|
|
|
62
62
|
})
|
|
63
63
|
|
|
64
64
|
output += buildGlobalParams({ moduleId, scriptSrcMode, loaderContext, isProduction, ctorType, jsonConfig, componentsMap, outputPath, genericsInfo, componentGenerics, hasApp })
|
|
65
|
+
if (!hasApp && i18n) {
|
|
66
|
+
output += buildI18n({ loaderContext })
|
|
67
|
+
}
|
|
65
68
|
output += getRequireScript({ ctorType, script, loaderContext })
|
|
66
69
|
output += `export default global.__mpxOptionsMap[${JSON.stringify(moduleId)}]\n`
|
|
67
70
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
const Template = require('webpack/lib/Template')
|
|
2
|
+
const RuntimeModule = require('webpack/lib/RuntimeModule')
|
|
3
|
+
|
|
4
|
+
const RetryRuntimeGlobal = '__webpack_require__.__retry'
|
|
5
|
+
|
|
6
|
+
class RetryRuntimeModule extends RuntimeModule {
|
|
7
|
+
constructor () {
|
|
8
|
+
super('mpx retry module')
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
generate () {
|
|
12
|
+
const { compilation } = this
|
|
13
|
+
const { runtimeTemplate } = compilation
|
|
14
|
+
return Template.asString([
|
|
15
|
+
`${RetryRuntimeGlobal} = ${runtimeTemplate.basicFunction(
|
|
16
|
+
'fn, times, interval',
|
|
17
|
+
[
|
|
18
|
+
'times = times || 1;',
|
|
19
|
+
'interval = interval || 0;',
|
|
20
|
+
`return new Promise(${runtimeTemplate.basicFunction(
|
|
21
|
+
'resolve, reject',
|
|
22
|
+
[
|
|
23
|
+
Template.indent([
|
|
24
|
+
'var _t = 0;',
|
|
25
|
+
`var _retry = ${runtimeTemplate.basicFunction('', [
|
|
26
|
+
Template.indent([
|
|
27
|
+
`fn().then(resolve).catch(${runtimeTemplate.basicFunction('err', [
|
|
28
|
+
Template.indent([
|
|
29
|
+
'if (_t < times) {',
|
|
30
|
+
Template.indent([
|
|
31
|
+
'++_t;',
|
|
32
|
+
'interval > 0 ? setTimeout(_retry, interval) : _retry()'
|
|
33
|
+
]),
|
|
34
|
+
'} else {',
|
|
35
|
+
Template.indent([
|
|
36
|
+
'reject(err);'
|
|
37
|
+
]),
|
|
38
|
+
'}'
|
|
39
|
+
])
|
|
40
|
+
])})`
|
|
41
|
+
])
|
|
42
|
+
])};`,
|
|
43
|
+
'_retry();'
|
|
44
|
+
])
|
|
45
|
+
]
|
|
46
|
+
)})`
|
|
47
|
+
]
|
|
48
|
+
)}`
|
|
49
|
+
])
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
module.exports = {
|
|
54
|
+
RetryRuntimeModule,
|
|
55
|
+
RetryRuntimeGlobal
|
|
56
|
+
}
|
|
@@ -91,10 +91,19 @@ const AsyncSuspense = ({ type, chunkName, moduleId, innerProps, getLoading, getF
|
|
|
91
91
|
if (cancelled)
|
|
92
92
|
return;
|
|
93
93
|
if (type === 'component') {
|
|
94
|
-
global.
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
94
|
+
global.__mpxAppCbs.lazyLoad.forEach((cb) => {
|
|
95
|
+
// eslint-disable-next-line node/no-callback-literal
|
|
96
|
+
cb({
|
|
97
|
+
type: 'subpackage',
|
|
98
|
+
subpackage: [chunkName],
|
|
99
|
+
errMsg: `loadSubpackage: ${e.type}`
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
if (type === 'page' && typeof mpxGlobal.__mpx.config?.rnConfig?.lazyLoadPageErrorHandler === 'function') {
|
|
104
|
+
mpxGlobal.__mpx.config.rnConfig.lazyLoadPageErrorHandler({
|
|
105
|
+
subpackage: chunkName,
|
|
106
|
+
errType: e.type
|
|
98
107
|
});
|
|
99
108
|
}
|
|
100
109
|
loadChunkPromise.current = null;
|
|
@@ -117,14 +117,13 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
117
117
|
// 记录元素的偏移量
|
|
118
118
|
const offset = useSharedValue(getOffset(props.current || 0, initStep));
|
|
119
119
|
const strAbso = 'absolute' + dir.toUpperCase();
|
|
120
|
+
const strVelocity = 'velocity' + dir.toUpperCase();
|
|
120
121
|
// 标识手指触摸和抬起, 起点在onBegin
|
|
121
122
|
const touchfinish = useSharedValue(true);
|
|
122
123
|
// 记录上一帧的绝对定位坐标
|
|
123
124
|
const preAbsolutePos = useSharedValue(0);
|
|
124
125
|
// 记录从onBegin 到 onTouchesUp 时移动的距离
|
|
125
126
|
const moveTranstion = useSharedValue(0);
|
|
126
|
-
// 记录从onBegin 到 onTouchesUp 的时间
|
|
127
|
-
const moveTime = useSharedValue(0);
|
|
128
127
|
const timerId = useRef(0);
|
|
129
128
|
const intervalTimer = props.interval || 500;
|
|
130
129
|
const simultaneousHandlers = flatGesture(originSimultaneousHandlers);
|
|
@@ -405,7 +404,11 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
405
404
|
}
|
|
406
405
|
}, [children.length]);
|
|
407
406
|
useEffect(() => {
|
|
408
|
-
|
|
407
|
+
// 1. 如果用户在touch的过程中, 外部更新了current以外部为准(小程序表现)
|
|
408
|
+
// 2. 手指滑动过程中更新索引,外部会把current再传入进来,导致offset直接更新,增加判断不同才更新
|
|
409
|
+
if (props.current !== currentIndex.value) {
|
|
410
|
+
updateCurrent(props.current || 0, step.value);
|
|
411
|
+
}
|
|
409
412
|
}, [props.current]);
|
|
410
413
|
useEffect(() => {
|
|
411
414
|
autoplayShared.value = autoplay;
|
|
@@ -427,7 +430,7 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
427
430
|
function getTargetPosition(eventData) {
|
|
428
431
|
'worklet';
|
|
429
432
|
// 移动的距离
|
|
430
|
-
const {
|
|
433
|
+
const { transdir } = eventData;
|
|
431
434
|
let resetOffsetPos = 0;
|
|
432
435
|
let selectedIndex = currentIndex.value;
|
|
433
436
|
// 是否临界点
|
|
@@ -435,9 +438,9 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
435
438
|
// 真实滚动到的偏移量坐标
|
|
436
439
|
let moveToTargetPos = 0;
|
|
437
440
|
const tmp = !circularShared.value ? 0 : preMarginShared.value;
|
|
438
|
-
const currentOffset =
|
|
441
|
+
const currentOffset = transdir < 0 ? offset.value - tmp : offset.value + tmp;
|
|
439
442
|
const computedIndex = Math.abs(currentOffset) / step.value;
|
|
440
|
-
const moveToIndex =
|
|
443
|
+
const moveToIndex = transdir < 0 ? Math.ceil(computedIndex) : Math.floor(computedIndex);
|
|
441
444
|
// 实际应该定位的索引值
|
|
442
445
|
if (!circularShared.value) {
|
|
443
446
|
selectedIndex = moveToIndex;
|
|
@@ -470,14 +473,18 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
470
473
|
}
|
|
471
474
|
function canMove(eventData) {
|
|
472
475
|
'worklet';
|
|
473
|
-
|
|
474
|
-
|
|
476
|
+
// 旧版:如果在快速多次滑动时,只根据当前的offset判断,会出现offset没超出,加上translation后越界的场景(如在倒数第二个元素快速滑动)
|
|
477
|
+
// 新版:会加上translation
|
|
478
|
+
const { translation, transdir } = eventData;
|
|
479
|
+
const gestureMovePos = offset.value + translation;
|
|
475
480
|
if (!circularShared.value) {
|
|
476
|
-
|
|
477
|
-
|
|
481
|
+
// 如果只判断区间,中间非滑动状态(handleResistanceMove)向左滑动,突然改为向右滑动,但是还在非滑动态,本应该可滑动判断为了不可滑动
|
|
482
|
+
const posEnd = -step.value * (childrenLength.value - 1);
|
|
483
|
+
if (transdir < 0) {
|
|
484
|
+
return gestureMovePos > posEnd;
|
|
478
485
|
}
|
|
479
486
|
else {
|
|
480
|
-
return
|
|
487
|
+
return gestureMovePos < 0;
|
|
481
488
|
}
|
|
482
489
|
}
|
|
483
490
|
else {
|
|
@@ -511,25 +518,16 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
511
518
|
});
|
|
512
519
|
}
|
|
513
520
|
}
|
|
514
|
-
function handleBackInit() {
|
|
515
|
-
'worklet';
|
|
516
|
-
// 微信的效果
|
|
517
|
-
// 1. 只有一个元素,即使设置了circular,也不会产生循环的效果,2. 可以响应手势,但是会有回弹的效果
|
|
518
|
-
offset.value = withTiming(0, {
|
|
519
|
-
duration: easeDuration,
|
|
520
|
-
easing: easeMap[easeingFunc]
|
|
521
|
-
});
|
|
522
|
-
}
|
|
523
521
|
function handleBack(eventData) {
|
|
524
522
|
'worklet';
|
|
525
|
-
const {
|
|
523
|
+
const { transdir } = eventData;
|
|
526
524
|
// 向右滑动的back:trans < 0, 向左滑动的back: trans < 0
|
|
527
525
|
let currentOffset = Math.abs(offset.value);
|
|
528
526
|
if (circularShared.value) {
|
|
529
|
-
currentOffset +=
|
|
527
|
+
currentOffset += transdir < 0 ? preMarginShared.value : -preMarginShared.value;
|
|
530
528
|
}
|
|
531
529
|
const curIndex = currentOffset / step.value;
|
|
532
|
-
const moveToIndex = (
|
|
530
|
+
const moveToIndex = (transdir < 0 ? Math.floor(curIndex) : Math.ceil(curIndex)) - patchElmNumShared.value;
|
|
533
531
|
const targetOffset = -(moveToIndex + patchElmNumShared.value) * step.value + (circularShared.value ? preMarginShared.value : 0);
|
|
534
532
|
offset.value = withTiming(targetOffset, {
|
|
535
533
|
duration: easeDuration,
|
|
@@ -541,65 +539,111 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
541
539
|
}
|
|
542
540
|
});
|
|
543
541
|
}
|
|
544
|
-
|
|
542
|
+
// 当前的offset和index多对应的offset进行对比,判断是否超过一半
|
|
543
|
+
function computeHalf(eventData) {
|
|
545
544
|
'worklet';
|
|
545
|
+
const { transdir } = eventData;
|
|
546
546
|
const currentOffset = Math.abs(offset.value);
|
|
547
547
|
let preOffset = (currentIndex.value + patchElmNumShared.value) * step.value;
|
|
548
548
|
if (circularShared.value) {
|
|
549
549
|
preOffset -= preMarginShared.value;
|
|
550
550
|
}
|
|
551
|
-
// 正常事件中拿到的
|
|
551
|
+
// 正常事件中拿到的translation值(正向滑动<0,倒着滑>0)
|
|
552
552
|
const diffOffset = preOffset - currentOffset;
|
|
553
553
|
const half = Math.abs(diffOffset) > step.value / 2;
|
|
554
|
+
const isTriggerUpdateHalf = (transdir < 0 && currentOffset < preOffset) || (transdir > 0 && currentOffset > preOffset);
|
|
555
|
+
return {
|
|
556
|
+
diffOffset,
|
|
557
|
+
half,
|
|
558
|
+
isTriggerUpdateHalf
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
function handleLongPress(eventData) {
|
|
562
|
+
'worklet';
|
|
563
|
+
const { diffOffset, half, isTriggerUpdateHalf } = computeHalf(eventData);
|
|
554
564
|
if (+diffOffset === 0) {
|
|
555
565
|
runOnJS(resumeLoop)();
|
|
556
566
|
}
|
|
567
|
+
else if (isTriggerUpdateHalf) {
|
|
568
|
+
// 如果触发了onUpdate时的索引变更,则直接以update时的index为准
|
|
569
|
+
const targetIndex = !circularShared.value ? currentIndex.value : currentIndex.value + patchElmNumShared.value - 1;
|
|
570
|
+
offset.value = withTiming(-targetIndex * step.value, {
|
|
571
|
+
duration: easeDuration,
|
|
572
|
+
easing: easeMap[easeingFunc]
|
|
573
|
+
}, () => {
|
|
574
|
+
if (touchfinish.value !== false) {
|
|
575
|
+
currentIndex.value = targetIndex;
|
|
576
|
+
runOnJS(resumeLoop)();
|
|
577
|
+
}
|
|
578
|
+
});
|
|
579
|
+
}
|
|
557
580
|
else if (half) {
|
|
558
|
-
handleEnd(
|
|
581
|
+
handleEnd(eventData);
|
|
559
582
|
}
|
|
560
583
|
else {
|
|
561
|
-
handleBack(
|
|
584
|
+
handleBack(eventData);
|
|
562
585
|
}
|
|
563
586
|
}
|
|
564
587
|
function reachBoundary(eventData) {
|
|
565
588
|
'worklet';
|
|
566
|
-
//
|
|
589
|
+
// 1. 基于当前的offset和translation判断是否超过当前边界值
|
|
567
590
|
const { translation } = eventData;
|
|
568
|
-
const
|
|
591
|
+
const boundaryStart = -patchElmNumShared.value * step.value;
|
|
592
|
+
const boundaryEnd = -(childrenLength.value + patchElmNumShared.value) * step.value;
|
|
593
|
+
const moveToOffset = offset.value + translation;
|
|
569
594
|
let isBoundary = false;
|
|
570
595
|
let resetOffset = 0;
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
if (currentOffset < -posEnd + step.value) {
|
|
578
|
-
isBoundary = true;
|
|
579
|
-
resetOffset = Math.abs(moveStep) === 0 ? patchElmNumShared.value * step.value + translation : moveStep * elementsLength;
|
|
580
|
-
}
|
|
581
|
-
if (currentOffset > -posReverseEnd) {
|
|
582
|
-
isBoundary = true;
|
|
583
|
-
resetOffset = moveStep * elementsLength;
|
|
584
|
-
}
|
|
596
|
+
if (moveToOffset < boundaryEnd) {
|
|
597
|
+
isBoundary = true;
|
|
598
|
+
// 超过边界的距离
|
|
599
|
+
const exceedLength = Math.abs(moveToOffset) - Math.abs(boundaryEnd);
|
|
600
|
+
// 计算对标正常元素所在的offset
|
|
601
|
+
resetOffset = patchElmNumShared.value * step.value + exceedLength;
|
|
585
602
|
}
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
}
|
|
593
|
-
if (currentOffset < -posReverseEnd) {
|
|
594
|
-
isBoundary = true;
|
|
595
|
-
resetOffset = moveStep * elementsLength + patchElmNumShared.value * step.value;
|
|
596
|
-
}
|
|
603
|
+
if (moveToOffset > boundaryStart) {
|
|
604
|
+
isBoundary = true;
|
|
605
|
+
// 超过边界的距离
|
|
606
|
+
const exceedLength = Math.abs(boundaryStart) - Math.abs(moveToOffset);
|
|
607
|
+
// 计算对标正常元素所在的offset
|
|
608
|
+
resetOffset = (patchElmNumShared.value + childrenLength.value - 1) * step.value + (step.value - exceedLength);
|
|
597
609
|
}
|
|
598
610
|
return {
|
|
599
611
|
isBoundary,
|
|
600
612
|
resetOffset: -resetOffset
|
|
601
613
|
};
|
|
602
614
|
}
|
|
615
|
+
// 非循环超出边界,应用阻力; 开始滑动少阻力小,滑动越长阻力越大
|
|
616
|
+
function handleResistanceMove(eventData) {
|
|
617
|
+
'worklet';
|
|
618
|
+
const { translation, transdir } = eventData;
|
|
619
|
+
const moveToOffset = offset.value + translation;
|
|
620
|
+
const maxOverDrag = Math.floor(step.value / 2);
|
|
621
|
+
const maxOffset = translation < 0 ? -(childrenLength.value - 1) * step.value : 0;
|
|
622
|
+
let resistance = 0.1;
|
|
623
|
+
let overDrag = 0;
|
|
624
|
+
let finalOffset = 0;
|
|
625
|
+
// 向右向下小于0, 向左向上大于0;
|
|
626
|
+
if (transdir < 0) {
|
|
627
|
+
overDrag = Math.abs(moveToOffset - maxOffset);
|
|
628
|
+
}
|
|
629
|
+
else {
|
|
630
|
+
overDrag = Math.abs(moveToOffset);
|
|
631
|
+
}
|
|
632
|
+
// 滑动越多resistance越小
|
|
633
|
+
resistance = 1 - overDrag / maxOverDrag;
|
|
634
|
+
// 确保阻力在合理范围内
|
|
635
|
+
resistance = Math.min(0.5, resistance);
|
|
636
|
+
// 限制在最大拖拽范围内
|
|
637
|
+
if (transdir < 0) {
|
|
638
|
+
const adjustOffset = offset.value + translation * resistance;
|
|
639
|
+
finalOffset = Math.max(adjustOffset, maxOffset - maxOverDrag);
|
|
640
|
+
}
|
|
641
|
+
else {
|
|
642
|
+
const adjustOffset = offset.value + translation * resistance;
|
|
643
|
+
finalOffset = Math.min(adjustOffset, maxOverDrag);
|
|
644
|
+
}
|
|
645
|
+
return finalOffset;
|
|
646
|
+
}
|
|
603
647
|
const gesturePan = Gesture.Pan()
|
|
604
648
|
.onBegin((e) => {
|
|
605
649
|
'worklet';
|
|
@@ -610,21 +654,42 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
610
654
|
runOnJS(pauseLoop)();
|
|
611
655
|
preAbsolutePos.value = e[strAbso];
|
|
612
656
|
moveTranstion.value = e[strAbso];
|
|
613
|
-
moveTime.value = new Date().getTime();
|
|
614
657
|
})
|
|
615
|
-
.
|
|
658
|
+
.onUpdate((e) => {
|
|
616
659
|
'worklet';
|
|
617
660
|
if (touchfinish.value)
|
|
618
661
|
return;
|
|
619
|
-
const
|
|
620
|
-
const moveDistance = touchEventData[strAbso] - preAbsolutePos.value;
|
|
662
|
+
const moveDistance = e[strAbso] - preAbsolutePos.value;
|
|
621
663
|
const eventData = {
|
|
622
|
-
translation: moveDistance
|
|
664
|
+
translation: moveDistance,
|
|
665
|
+
transdir: moveDistance !== 0 ? moveDistance : e[strAbso] - moveTranstion.value
|
|
623
666
|
};
|
|
624
|
-
//
|
|
625
|
-
|
|
667
|
+
// 1. 支持滑动中超出一半更新索引的能力:只更新索引并不会影响onFinalize依据当前offset计算的索引
|
|
668
|
+
const { half } = computeHalf(eventData);
|
|
669
|
+
if (childrenLength.value > 1 && half) {
|
|
670
|
+
const { selectedIndex } = getTargetPosition(eventData);
|
|
671
|
+
currentIndex.value = selectedIndex;
|
|
672
|
+
}
|
|
673
|
+
// 2. 非循环: 处理用户一直拖拽到临界点的场景,如果放到onFinalize无法阻止offset.value更新为越界的值
|
|
674
|
+
if (!circularShared.value) {
|
|
675
|
+
if (canMove(eventData)) {
|
|
676
|
+
offset.value = moveDistance + offset.value;
|
|
677
|
+
}
|
|
678
|
+
else {
|
|
679
|
+
const finalOffset = handleResistanceMove(eventData);
|
|
680
|
+
offset.value = finalOffset;
|
|
681
|
+
}
|
|
682
|
+
preAbsolutePos.value = e[strAbso];
|
|
626
683
|
return;
|
|
627
684
|
}
|
|
685
|
+
// 3. 循环更新: 只有一个元素时可滑动,加入阻力
|
|
686
|
+
if (circularShared.value && childrenLength.value === 1) {
|
|
687
|
+
const finalOffset = handleResistanceMove(eventData);
|
|
688
|
+
offset.value = finalOffset;
|
|
689
|
+
preAbsolutePos.value = e[strAbso];
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
692
|
+
// 4. 循环更新:正常
|
|
628
693
|
const { isBoundary, resetOffset } = reachBoundary(eventData);
|
|
629
694
|
if (childrenLength.value > 1 && isBoundary && circularShared.value) {
|
|
630
695
|
offset.value = resetOffset;
|
|
@@ -632,28 +697,43 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
632
697
|
else {
|
|
633
698
|
offset.value = moveDistance + offset.value;
|
|
634
699
|
}
|
|
635
|
-
preAbsolutePos.value =
|
|
700
|
+
preAbsolutePos.value = e[strAbso];
|
|
636
701
|
})
|
|
637
|
-
.
|
|
702
|
+
.onFinalize((e) => {
|
|
638
703
|
'worklet';
|
|
639
704
|
if (touchfinish.value)
|
|
640
705
|
return;
|
|
641
|
-
const touchEventData = e.changedTouches[0];
|
|
642
|
-
const moveDistance = touchEventData[strAbso] - moveTranstion.value;
|
|
643
706
|
touchfinish.value = true;
|
|
707
|
+
// 触发过onUpdate正常情况下e[strAbso] - preAbsolutePos.value=0; 未触发过onUpdate的情况下e[strAbso] - preAbsolutePos.value 不为0
|
|
708
|
+
const moveDistance = e[strAbso] - preAbsolutePos.value;
|
|
644
709
|
const eventData = {
|
|
645
|
-
translation: moveDistance
|
|
710
|
+
translation: moveDistance,
|
|
711
|
+
transdir: moveDistance !== 0 ? moveDistance : e[strAbso] - moveTranstion.value
|
|
646
712
|
};
|
|
713
|
+
// 1. 只有一个元素:循环 和 非循环状态,都走回弹效果
|
|
647
714
|
if (childrenLength.value === 1) {
|
|
648
|
-
|
|
715
|
+
offset.value = withTiming(0, {
|
|
716
|
+
duration: easeDuration,
|
|
717
|
+
easing: easeMap[easeingFunc]
|
|
718
|
+
});
|
|
719
|
+
return;
|
|
649
720
|
}
|
|
650
|
-
//
|
|
721
|
+
// 2.非循环状态不可移动态:最后一个元素 和 第一个元素
|
|
722
|
+
// 非循环支持最后元素可滑动能力后,向左快速移动未超过最大可移动范围一半,因为offset为正值,向左滑动handleBack,默认向上取整
|
|
723
|
+
// 但是在offset大于0时,取0。[-100, 0](back取0), [0, 100](back取1), 所以handleLongPress里的处理逻辑需要兼容支持,因此这里直接单独处理,不耦合下方公共的判断逻辑。
|
|
651
724
|
if (!circularShared.value && !canMove(eventData)) {
|
|
725
|
+
if (eventData.transdir < 0) {
|
|
726
|
+
handleBack(eventData);
|
|
727
|
+
}
|
|
728
|
+
else {
|
|
729
|
+
handleEnd(eventData);
|
|
730
|
+
}
|
|
652
731
|
return;
|
|
653
732
|
}
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
733
|
+
// 3. 非循环状态可移动态、循环状态, 正常逻辑处理
|
|
734
|
+
const velocity = e[strVelocity];
|
|
735
|
+
if (Math.abs(velocity) < longPressRatio) {
|
|
736
|
+
handleLongPress(eventData);
|
|
657
737
|
}
|
|
658
738
|
else {
|
|
659
739
|
handleEnd(eventData);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useEffect, useMemo, useRef } from 'react';
|
|
2
2
|
import { Easing, useSharedValue, withTiming, useAnimatedStyle, withSequence, withDelay, makeMutable, cancelAnimation, runOnJS } from 'react-native-reanimated';
|
|
3
3
|
import { error, hasOwn, collectDataset } from '@mpxjs/utils';
|
|
4
|
+
import { useRunOnJSCallback } from './utils';
|
|
4
5
|
// 微信 timingFunction 和 RN Easing 对应关系
|
|
5
6
|
const EasingKey = {
|
|
6
7
|
linear: Easing.linear,
|
|
@@ -182,13 +183,19 @@ export default function useAnimationHooks(props) {
|
|
|
182
183
|
timeStamp: Date.now()
|
|
183
184
|
});
|
|
184
185
|
}
|
|
186
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
187
|
+
const runOnJSCallbackRef = useRef({
|
|
188
|
+
withTimingCallback
|
|
189
|
+
});
|
|
190
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
191
|
+
const runOnJSCallback = useRunOnJSCallback(runOnJSCallbackRef);
|
|
185
192
|
// 创建单个animation
|
|
186
193
|
function getAnimation({ key, value }, { delay, duration, easing }, callback) {
|
|
187
194
|
const animation = typeof callback === 'function'
|
|
188
195
|
? withTiming(value, { duration, easing }, (finished, current) => {
|
|
189
196
|
callback(finished, current);
|
|
190
197
|
if (transitionend && finished) {
|
|
191
|
-
runOnJS(
|
|
198
|
+
runOnJS(runOnJSCallback)('withTimingCallback', finished, current, duration);
|
|
192
199
|
}
|
|
193
200
|
})
|
|
194
201
|
: withTiming(value, { duration, easing });
|
|
@@ -5,7 +5,6 @@ import { VarContext, ScrollViewContext, RouteContext } from './context';
|
|
|
5
5
|
import { ExpressionParser, parseFunc, ReplaceSource } from './parser';
|
|
6
6
|
import { initialWindowMetrics } from 'react-native-safe-area-context';
|
|
7
7
|
import FastImage from '@d11/react-native-fast-image';
|
|
8
|
-
import { runOnJS } from 'react-native-reanimated';
|
|
9
8
|
import { Gesture } from 'react-native-gesture-handler';
|
|
10
9
|
export const TEXT_STYLE_REGEX = /color|font.*|text.*|letterSpacing|lineHeight|includeFontPadding|writingDirection/;
|
|
11
10
|
export const PERCENT_REGEX = /^\s*-?\d+(\.\d+)?%\s*$/;
|
|
@@ -663,13 +662,11 @@ export function useHover({ enableHover, hoverStartTime, hoverStayTime, disabled
|
|
|
663
662
|
const gesture = useMemo(() => {
|
|
664
663
|
return Gesture.Pan()
|
|
665
664
|
.onTouchesDown(() => {
|
|
666
|
-
|
|
667
|
-
runOnJS(setStartTimer)();
|
|
665
|
+
setStartTimer();
|
|
668
666
|
})
|
|
669
667
|
.onTouchesUp(() => {
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
});
|
|
668
|
+
setStayTimer();
|
|
669
|
+
}).runOnJS(true);
|
|
673
670
|
}, []);
|
|
674
671
|
if (gestureRef) {
|
|
675
672
|
gesture.simultaneousWithExternalGesture(gestureRef);
|
|
@@ -679,3 +676,17 @@ export function useHover({ enableHover, hoverStartTime, hoverStayTime, disabled
|
|
|
679
676
|
gesture
|
|
680
677
|
};
|
|
681
678
|
}
|
|
679
|
+
export function useRunOnJSCallback(callbackMapRef) {
|
|
680
|
+
const invokeCallback = useCallback((key, ...args) => {
|
|
681
|
+
const callback = callbackMapRef.current[key];
|
|
682
|
+
// eslint-disable-next-line node/no-callback-literal
|
|
683
|
+
if (isFunction(callback))
|
|
684
|
+
return callback(...args);
|
|
685
|
+
}, []);
|
|
686
|
+
useEffect(() => {
|
|
687
|
+
return () => {
|
|
688
|
+
callbackMapRef.current = {};
|
|
689
|
+
};
|
|
690
|
+
}, []);
|
|
691
|
+
return invokeCallback;
|
|
692
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useState, ComponentType, useEffect, useCallback, useRef, ReactNode, createElement } from 'react'
|
|
2
2
|
import { View, Image, StyleSheet, Text, TouchableOpacity } from 'react-native'
|
|
3
3
|
import FastImage from '@d11/react-native-fast-image'
|
|
4
|
+
import { AnyFunc } from './types/common'
|
|
4
5
|
|
|
5
6
|
const asyncChunkMap = new Map()
|
|
6
7
|
|
|
@@ -136,10 +137,19 @@ const AsyncSuspense: React.FC<AsyncSuspenseProps> = ({
|
|
|
136
137
|
.catch((e) => {
|
|
137
138
|
if (cancelled) return
|
|
138
139
|
if (type === 'component') {
|
|
139
|
-
global.
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
140
|
+
global.__mpxAppCbs.lazyLoad.forEach((cb: AnyFunc) => {
|
|
141
|
+
// eslint-disable-next-line node/no-callback-literal
|
|
142
|
+
cb({
|
|
143
|
+
type: 'subpackage',
|
|
144
|
+
subpackage: [chunkName],
|
|
145
|
+
errMsg: `loadSubpackage: ${e.type}`
|
|
146
|
+
})
|
|
147
|
+
})
|
|
148
|
+
}
|
|
149
|
+
if (type === 'page' && typeof mpxGlobal.__mpx.config?.rnConfig?.lazyLoadPageErrorHandler === 'function') {
|
|
150
|
+
mpxGlobal.__mpx.config.rnConfig.lazyLoadPageErrorHandler({
|
|
151
|
+
subpackage: chunkName,
|
|
152
|
+
errType: e.type
|
|
143
153
|
})
|
|
144
154
|
}
|
|
145
155
|
loadChunkPromise.current = null
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { View, NativeSyntheticEvent, LayoutChangeEvent } from 'react-native'
|
|
2
|
-
import { GestureDetector, Gesture, PanGesture } from 'react-native-gesture-handler'
|
|
2
|
+
import { GestureDetector, Gesture, PanGesture, GestureStateChangeEvent, PanGestureHandlerEventPayload } from 'react-native-gesture-handler'
|
|
3
3
|
import Animated, { useAnimatedStyle, useSharedValue, withTiming, Easing, runOnJS, useAnimatedReaction, cancelAnimation } from 'react-native-reanimated'
|
|
4
4
|
|
|
5
5
|
import React, { JSX, forwardRef, useRef, useEffect, ReactNode, ReactElement, useMemo, createElement } from 'react'
|
|
@@ -26,8 +26,12 @@ import Portal from './mpx-portal'
|
|
|
26
26
|
*/
|
|
27
27
|
type EaseType = 'default' | 'linear' | 'easeInCubic' | 'easeOutCubic' | 'easeInOutCubic'
|
|
28
28
|
type StrAbsoType = 'absoluteX' | 'absoluteY'
|
|
29
|
+
type StrVelocityType = 'velocityX' | 'velocityY'
|
|
29
30
|
type EventDataType = {
|
|
31
|
+
// 和上一帧offset值的对比
|
|
30
32
|
translation: number
|
|
33
|
+
// onUpdate时根据上一个判断方向,onFinalize根据transformStart判断
|
|
34
|
+
transdir: number
|
|
31
35
|
}
|
|
32
36
|
|
|
33
37
|
interface SwiperProps {
|
|
@@ -46,7 +50,7 @@ interface SwiperProps {
|
|
|
46
50
|
vertical?: boolean
|
|
47
51
|
style: {
|
|
48
52
|
[key: string]: any
|
|
49
|
-
}
|
|
53
|
+
}
|
|
50
54
|
'easing-function'?: EaseType
|
|
51
55
|
'previous-margin'?: string
|
|
52
56
|
'next-margin'?: string
|
|
@@ -54,7 +58,7 @@ interface SwiperProps {
|
|
|
54
58
|
'enable-var': boolean
|
|
55
59
|
'parent-font-size'?: number
|
|
56
60
|
'parent-width'?: number
|
|
57
|
-
'parent-height'?: number
|
|
61
|
+
'parent-height'?: number
|
|
58
62
|
'external-var-context'?: Record<string, any>
|
|
59
63
|
'wait-for'?: Array<GestureHandler>
|
|
60
64
|
'simultaneous-handlers'?: Array<GestureHandler>
|
|
@@ -199,14 +203,13 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
199
203
|
// 记录元素的偏移量
|
|
200
204
|
const offset = useSharedValue(getOffset(props.current || 0, initStep))
|
|
201
205
|
const strAbso = 'absolute' + dir.toUpperCase() as StrAbsoType
|
|
206
|
+
const strVelocity = 'velocity' + dir.toUpperCase() as StrVelocityType
|
|
202
207
|
// 标识手指触摸和抬起, 起点在onBegin
|
|
203
208
|
const touchfinish = useSharedValue(true)
|
|
204
209
|
// 记录上一帧的绝对定位坐标
|
|
205
210
|
const preAbsolutePos = useSharedValue(0)
|
|
206
211
|
// 记录从onBegin 到 onTouchesUp 时移动的距离
|
|
207
212
|
const moveTranstion = useSharedValue(0)
|
|
208
|
-
// 记录从onBegin 到 onTouchesUp 的时间
|
|
209
|
-
const moveTime = useSharedValue(0)
|
|
210
213
|
const timerId = useRef(0 as number | ReturnType<typeof setTimeout>)
|
|
211
214
|
const intervalTimer = props.interval || 500
|
|
212
215
|
|
|
@@ -505,7 +508,11 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
505
508
|
}, [children.length])
|
|
506
509
|
|
|
507
510
|
useEffect(() => {
|
|
508
|
-
|
|
511
|
+
// 1. 如果用户在touch的过程中, 外部更新了current以外部为准(小程序表现)
|
|
512
|
+
// 2. 手指滑动过程中更新索引,外部会把current再传入进来,导致offset直接更新,增加判断不同才更新
|
|
513
|
+
if (props.current !== currentIndex.value) {
|
|
514
|
+
updateCurrent(props.current || 0, step.value)
|
|
515
|
+
}
|
|
509
516
|
}, [props.current])
|
|
510
517
|
|
|
511
518
|
useEffect(() => {
|
|
@@ -529,7 +536,7 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
529
536
|
function getTargetPosition (eventData: EventDataType) {
|
|
530
537
|
'worklet'
|
|
531
538
|
// 移动的距离
|
|
532
|
-
const {
|
|
539
|
+
const { transdir } = eventData
|
|
533
540
|
let resetOffsetPos = 0
|
|
534
541
|
let selectedIndex = currentIndex.value
|
|
535
542
|
// 是否临界点
|
|
@@ -537,9 +544,9 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
537
544
|
// 真实滚动到的偏移量坐标
|
|
538
545
|
let moveToTargetPos = 0
|
|
539
546
|
const tmp = !circularShared.value ? 0 : preMarginShared.value
|
|
540
|
-
const currentOffset =
|
|
547
|
+
const currentOffset = transdir < 0 ? offset.value - tmp : offset.value + tmp
|
|
541
548
|
const computedIndex = Math.abs(currentOffset) / step.value
|
|
542
|
-
const moveToIndex =
|
|
549
|
+
const moveToIndex = transdir < 0 ? Math.ceil(computedIndex) : Math.floor(computedIndex)
|
|
543
550
|
// 实际应该定位的索引值
|
|
544
551
|
if (!circularShared.value) {
|
|
545
552
|
selectedIndex = moveToIndex
|
|
@@ -569,13 +576,17 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
569
576
|
}
|
|
570
577
|
function canMove (eventData: EventDataType) {
|
|
571
578
|
'worklet'
|
|
572
|
-
|
|
573
|
-
|
|
579
|
+
// 旧版:如果在快速多次滑动时,只根据当前的offset判断,会出现offset没超出,加上translation后越界的场景(如在倒数第二个元素快速滑动)
|
|
580
|
+
// 新版:会加上translation
|
|
581
|
+
const { translation, transdir } = eventData
|
|
582
|
+
const gestureMovePos = offset.value + translation
|
|
574
583
|
if (!circularShared.value) {
|
|
575
|
-
|
|
576
|
-
|
|
584
|
+
// 如果只判断区间,中间非滑动状态(handleResistanceMove)向左滑动,突然改为向右滑动,但是还在非滑动态,本应该可滑动判断为了不可滑动
|
|
585
|
+
const posEnd = -step.value * (childrenLength.value - 1)
|
|
586
|
+
if (transdir < 0) {
|
|
587
|
+
return gestureMovePos > posEnd
|
|
577
588
|
} else {
|
|
578
|
-
return
|
|
589
|
+
return gestureMovePos < 0
|
|
579
590
|
}
|
|
580
591
|
} else {
|
|
581
592
|
return true
|
|
@@ -607,25 +618,16 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
607
618
|
})
|
|
608
619
|
}
|
|
609
620
|
}
|
|
610
|
-
function handleBackInit () {
|
|
611
|
-
'worklet'
|
|
612
|
-
// 微信的效果
|
|
613
|
-
// 1. 只有一个元素,即使设置了circular,也不会产生循环的效果,2. 可以响应手势,但是会有回弹的效果
|
|
614
|
-
offset.value = withTiming(0, {
|
|
615
|
-
duration: easeDuration,
|
|
616
|
-
easing: easeMap[easeingFunc]
|
|
617
|
-
})
|
|
618
|
-
}
|
|
619
621
|
function handleBack (eventData: EventDataType) {
|
|
620
622
|
'worklet'
|
|
621
|
-
const {
|
|
623
|
+
const { transdir } = eventData
|
|
622
624
|
// 向右滑动的back:trans < 0, 向左滑动的back: trans < 0
|
|
623
625
|
let currentOffset = Math.abs(offset.value)
|
|
624
626
|
if (circularShared.value) {
|
|
625
|
-
currentOffset +=
|
|
627
|
+
currentOffset += transdir < 0 ? preMarginShared.value : -preMarginShared.value
|
|
626
628
|
}
|
|
627
629
|
const curIndex = currentOffset / step.value
|
|
628
|
-
const moveToIndex = (
|
|
630
|
+
const moveToIndex = (transdir < 0 ? Math.floor(curIndex) : Math.ceil(curIndex)) - patchElmNumShared.value
|
|
629
631
|
const targetOffset = -(moveToIndex + patchElmNumShared.value) * step.value + (circularShared.value ? preMarginShared.value : 0)
|
|
630
632
|
offset.value = withTiming(targetOffset, {
|
|
631
633
|
duration: easeDuration,
|
|
@@ -637,64 +639,108 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
637
639
|
}
|
|
638
640
|
})
|
|
639
641
|
}
|
|
640
|
-
|
|
642
|
+
// 当前的offset和index多对应的offset进行对比,判断是否超过一半
|
|
643
|
+
function computeHalf (eventData: EventDataType) {
|
|
641
644
|
'worklet'
|
|
645
|
+
const { transdir } = eventData
|
|
642
646
|
const currentOffset = Math.abs(offset.value)
|
|
643
647
|
let preOffset = (currentIndex.value + patchElmNumShared.value) * step.value
|
|
644
648
|
if (circularShared.value) {
|
|
645
649
|
preOffset -= preMarginShared.value
|
|
646
650
|
}
|
|
647
|
-
// 正常事件中拿到的
|
|
651
|
+
// 正常事件中拿到的translation值(正向滑动<0,倒着滑>0)
|
|
648
652
|
const diffOffset = preOffset - currentOffset
|
|
649
653
|
const half = Math.abs(diffOffset) > step.value / 2
|
|
654
|
+
const isTriggerUpdateHalf = (transdir < 0 && currentOffset < preOffset) || (transdir > 0 && currentOffset > preOffset)
|
|
655
|
+
return {
|
|
656
|
+
diffOffset,
|
|
657
|
+
half,
|
|
658
|
+
isTriggerUpdateHalf
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
function handleLongPress (eventData: EventDataType) {
|
|
662
|
+
'worklet'
|
|
663
|
+
const { diffOffset, half, isTriggerUpdateHalf } = computeHalf(eventData)
|
|
650
664
|
if (+diffOffset === 0) {
|
|
651
665
|
runOnJS(resumeLoop)()
|
|
666
|
+
} else if (isTriggerUpdateHalf) {
|
|
667
|
+
// 如果触发了onUpdate时的索引变更,则直接以update时的index为准
|
|
668
|
+
const targetIndex = !circularShared.value ? currentIndex.value : currentIndex.value + patchElmNumShared.value - 1
|
|
669
|
+
offset.value = withTiming(-targetIndex * step.value, {
|
|
670
|
+
duration: easeDuration,
|
|
671
|
+
easing: easeMap[easeingFunc]
|
|
672
|
+
}, () => {
|
|
673
|
+
if (touchfinish.value !== false) {
|
|
674
|
+
currentIndex.value = targetIndex
|
|
675
|
+
runOnJS(resumeLoop)()
|
|
676
|
+
}
|
|
677
|
+
})
|
|
652
678
|
} else if (half) {
|
|
653
|
-
handleEnd(
|
|
679
|
+
handleEnd(eventData)
|
|
654
680
|
} else {
|
|
655
|
-
handleBack(
|
|
681
|
+
handleBack(eventData)
|
|
656
682
|
}
|
|
657
683
|
}
|
|
658
684
|
function reachBoundary (eventData: EventDataType) {
|
|
659
685
|
'worklet'
|
|
660
|
-
//
|
|
686
|
+
// 1. 基于当前的offset和translation判断是否超过当前边界值
|
|
661
687
|
const { translation } = eventData
|
|
662
|
-
const
|
|
688
|
+
const boundaryStart = -patchElmNumShared.value * step.value
|
|
689
|
+
const boundaryEnd = -(childrenLength.value + patchElmNumShared.value) * step.value
|
|
690
|
+
const moveToOffset = offset.value + translation
|
|
663
691
|
let isBoundary = false
|
|
664
692
|
let resetOffset = 0
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
}
|
|
679
|
-
} else if (translation > 0) {
|
|
680
|
-
const posEnd = (patchElmNumShared.value - 1) * step.value
|
|
681
|
-
const posReverseEnd = (patchElmNumShared.value + childrenLength.value) * step.value
|
|
682
|
-
if (currentOffset > -posEnd) {
|
|
683
|
-
isBoundary = true
|
|
684
|
-
resetOffset = moveStep * elementsLength + step.value + (moveStep === 1 ? translation : 0)
|
|
685
|
-
}
|
|
686
|
-
if (currentOffset < -posReverseEnd) {
|
|
687
|
-
isBoundary = true
|
|
688
|
-
resetOffset = moveStep * elementsLength + patchElmNumShared.value * step.value
|
|
689
|
-
}
|
|
693
|
+
if (moveToOffset < boundaryEnd) {
|
|
694
|
+
isBoundary = true
|
|
695
|
+
// 超过边界的距离
|
|
696
|
+
const exceedLength = Math.abs(moveToOffset) - Math.abs(boundaryEnd)
|
|
697
|
+
// 计算对标正常元素所在的offset
|
|
698
|
+
resetOffset = patchElmNumShared.value * step.value + exceedLength
|
|
699
|
+
}
|
|
700
|
+
if (moveToOffset > boundaryStart) {
|
|
701
|
+
isBoundary = true
|
|
702
|
+
// 超过边界的距离
|
|
703
|
+
const exceedLength = Math.abs(boundaryStart) - Math.abs(moveToOffset)
|
|
704
|
+
// 计算对标正常元素所在的offset
|
|
705
|
+
resetOffset = (patchElmNumShared.value + childrenLength.value - 1) * step.value + (step.value - exceedLength)
|
|
690
706
|
}
|
|
691
707
|
return {
|
|
692
708
|
isBoundary,
|
|
693
709
|
resetOffset: -resetOffset
|
|
694
710
|
}
|
|
695
711
|
}
|
|
712
|
+
// 非循环超出边界,应用阻力; 开始滑动少阻力小,滑动越长阻力越大
|
|
713
|
+
function handleResistanceMove (eventData: EventDataType) {
|
|
714
|
+
'worklet'
|
|
715
|
+
const { translation, transdir } = eventData
|
|
716
|
+
const moveToOffset = offset.value + translation
|
|
717
|
+
const maxOverDrag = Math.floor(step.value / 2)
|
|
718
|
+
const maxOffset = translation < 0 ? -(childrenLength.value - 1) * step.value : 0
|
|
719
|
+
let resistance = 0.1
|
|
720
|
+
let overDrag = 0
|
|
721
|
+
let finalOffset = 0
|
|
722
|
+
// 向右向下小于0, 向左向上大于0;
|
|
723
|
+
if (transdir < 0) {
|
|
724
|
+
overDrag = Math.abs(moveToOffset - maxOffset)
|
|
725
|
+
} else {
|
|
726
|
+
overDrag = Math.abs(moveToOffset)
|
|
727
|
+
}
|
|
728
|
+
// 滑动越多resistance越小
|
|
729
|
+
resistance = 1 - overDrag / maxOverDrag
|
|
730
|
+
// 确保阻力在合理范围内
|
|
731
|
+
resistance = Math.min(0.5, resistance)
|
|
732
|
+
// 限制在最大拖拽范围内
|
|
733
|
+
if (transdir < 0) {
|
|
734
|
+
const adjustOffset = offset.value + translation * resistance
|
|
735
|
+
finalOffset = Math.max(adjustOffset, maxOffset - maxOverDrag)
|
|
736
|
+
} else {
|
|
737
|
+
const adjustOffset = offset.value + translation * resistance
|
|
738
|
+
finalOffset = Math.min(adjustOffset, maxOverDrag)
|
|
739
|
+
}
|
|
740
|
+
return finalOffset
|
|
741
|
+
}
|
|
696
742
|
const gesturePan = Gesture.Pan()
|
|
697
|
-
.onBegin((e) => {
|
|
743
|
+
.onBegin((e: GestureStateChangeEvent<PanGestureHandlerEventPayload>) => {
|
|
698
744
|
'worklet'
|
|
699
745
|
if (!step.value) return
|
|
700
746
|
touchfinish.value = false
|
|
@@ -702,47 +748,81 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
702
748
|
runOnJS(pauseLoop)()
|
|
703
749
|
preAbsolutePos.value = e[strAbso]
|
|
704
750
|
moveTranstion.value = e[strAbso]
|
|
705
|
-
moveTime.value = new Date().getTime()
|
|
706
751
|
})
|
|
707
|
-
.
|
|
752
|
+
.onUpdate((e: GestureStateChangeEvent<PanGestureHandlerEventPayload>) => {
|
|
708
753
|
'worklet'
|
|
709
754
|
if (touchfinish.value) return
|
|
710
|
-
const
|
|
711
|
-
const moveDistance = touchEventData[strAbso] - preAbsolutePos.value
|
|
755
|
+
const moveDistance = e[strAbso] - preAbsolutePos.value
|
|
712
756
|
const eventData = {
|
|
713
|
-
translation: moveDistance
|
|
757
|
+
translation: moveDistance,
|
|
758
|
+
transdir: moveDistance !== 0 ? moveDistance : e[strAbso] - moveTranstion.value
|
|
714
759
|
}
|
|
715
|
-
//
|
|
716
|
-
|
|
760
|
+
// 1. 支持滑动中超出一半更新索引的能力:只更新索引并不会影响onFinalize依据当前offset计算的索引
|
|
761
|
+
const { half } = computeHalf(eventData)
|
|
762
|
+
if (childrenLength.value > 1 && half) {
|
|
763
|
+
const { selectedIndex } = getTargetPosition(eventData)
|
|
764
|
+
currentIndex.value = selectedIndex
|
|
765
|
+
}
|
|
766
|
+
// 2. 非循环: 处理用户一直拖拽到临界点的场景,如果放到onFinalize无法阻止offset.value更新为越界的值
|
|
767
|
+
if (!circularShared.value) {
|
|
768
|
+
if (canMove(eventData)) {
|
|
769
|
+
offset.value = moveDistance + offset.value
|
|
770
|
+
} else {
|
|
771
|
+
const finalOffset = handleResistanceMove(eventData)
|
|
772
|
+
offset.value = finalOffset
|
|
773
|
+
}
|
|
774
|
+
preAbsolutePos.value = e[strAbso]
|
|
717
775
|
return
|
|
718
776
|
}
|
|
777
|
+
// 3. 循环更新: 只有一个元素时可滑动,加入阻力
|
|
778
|
+
if (circularShared.value && childrenLength.value === 1) {
|
|
779
|
+
const finalOffset = handleResistanceMove(eventData)
|
|
780
|
+
offset.value = finalOffset
|
|
781
|
+
preAbsolutePos.value = e[strAbso]
|
|
782
|
+
return
|
|
783
|
+
}
|
|
784
|
+
// 4. 循环更新:正常
|
|
719
785
|
const { isBoundary, resetOffset } = reachBoundary(eventData)
|
|
720
786
|
if (childrenLength.value > 1 && isBoundary && circularShared.value) {
|
|
721
787
|
offset.value = resetOffset
|
|
722
788
|
} else {
|
|
723
789
|
offset.value = moveDistance + offset.value
|
|
724
790
|
}
|
|
725
|
-
preAbsolutePos.value =
|
|
791
|
+
preAbsolutePos.value = e[strAbso]
|
|
726
792
|
})
|
|
727
|
-
.
|
|
793
|
+
.onFinalize((e: GestureStateChangeEvent<PanGestureHandlerEventPayload>) => {
|
|
728
794
|
'worklet'
|
|
729
795
|
if (touchfinish.value) return
|
|
730
|
-
const touchEventData = e.changedTouches[0]
|
|
731
|
-
const moveDistance = touchEventData[strAbso] - moveTranstion.value
|
|
732
796
|
touchfinish.value = true
|
|
797
|
+
// 触发过onUpdate正常情况下e[strAbso] - preAbsolutePos.value=0; 未触发过onUpdate的情况下e[strAbso] - preAbsolutePos.value 不为0
|
|
798
|
+
const moveDistance = e[strAbso] - preAbsolutePos.value
|
|
733
799
|
const eventData = {
|
|
734
|
-
translation: moveDistance
|
|
800
|
+
translation: moveDistance,
|
|
801
|
+
transdir: moveDistance !== 0 ? moveDistance : e[strAbso] - moveTranstion.value
|
|
735
802
|
}
|
|
803
|
+
// 1. 只有一个元素:循环 和 非循环状态,都走回弹效果
|
|
736
804
|
if (childrenLength.value === 1) {
|
|
737
|
-
|
|
805
|
+
offset.value = withTiming(0, {
|
|
806
|
+
duration: easeDuration,
|
|
807
|
+
easing: easeMap[easeingFunc]
|
|
808
|
+
})
|
|
809
|
+
return
|
|
738
810
|
}
|
|
739
|
-
//
|
|
811
|
+
// 2.非循环状态不可移动态:最后一个元素 和 第一个元素
|
|
812
|
+
// 非循环支持最后元素可滑动能力后,向左快速移动未超过最大可移动范围一半,因为offset为正值,向左滑动handleBack,默认向上取整
|
|
813
|
+
// 但是在offset大于0时,取0。[-100, 0](back取0), [0, 100](back取1), 所以handleLongPress里的处理逻辑需要兼容支持,因此这里直接单独处理,不耦合下方公共的判断逻辑。
|
|
740
814
|
if (!circularShared.value && !canMove(eventData)) {
|
|
815
|
+
if (eventData.transdir < 0) {
|
|
816
|
+
handleBack(eventData)
|
|
817
|
+
} else {
|
|
818
|
+
handleEnd(eventData)
|
|
819
|
+
}
|
|
741
820
|
return
|
|
742
821
|
}
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
822
|
+
// 3. 非循环状态可移动态、循环状态, 正常逻辑处理
|
|
823
|
+
const velocity = e[strVelocity]
|
|
824
|
+
if (Math.abs(velocity) < longPressRatio) {
|
|
825
|
+
handleLongPress(eventData)
|
|
746
826
|
} else {
|
|
747
827
|
handleEnd(eventData)
|
|
748
828
|
}
|
|
@@ -40,6 +40,8 @@ declare let global: {
|
|
|
40
40
|
__formatValue (value: string): string | number
|
|
41
41
|
} & Record<string, any>
|
|
42
42
|
|
|
43
|
+
declare let mpxGlobal: Record<string, any>
|
|
44
|
+
|
|
43
45
|
declare module '@react-navigation/native' {
|
|
44
46
|
export function useNavigation (): Record<string, any>
|
|
45
47
|
export function usePreventRemove(
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
} from 'react-native-reanimated'
|
|
15
15
|
import type { AnimationCallback, WithTimingConfig, SharedValue, AnimatableValue } from 'react-native-reanimated'
|
|
16
16
|
import { error, hasOwn, collectDataset } from '@mpxjs/utils'
|
|
17
|
+
import { useRunOnJSCallback } from './utils'
|
|
17
18
|
import { ExtendedViewStyle } from './types/common'
|
|
18
19
|
import type { _ViewProps } from './mpx-view'
|
|
19
20
|
|
|
@@ -218,13 +219,19 @@ export default function useAnimationHooks<T, P> (props: _ViewProps & { enableAni
|
|
|
218
219
|
timeStamp: Date.now()
|
|
219
220
|
})
|
|
220
221
|
}
|
|
222
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
223
|
+
const runOnJSCallbackRef = useRef({
|
|
224
|
+
withTimingCallback
|
|
225
|
+
})
|
|
226
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
227
|
+
const runOnJSCallback = useRunOnJSCallback(runOnJSCallbackRef)
|
|
221
228
|
// 创建单个animation
|
|
222
229
|
function getAnimation ({ key, value }: { key: string, value: string|number }, { delay, duration, easing }: ExtendWithTimingConfig, callback?: AnimationCallback) {
|
|
223
230
|
const animation = typeof callback === 'function'
|
|
224
231
|
? withTiming(value, { duration, easing }, (finished, current) => {
|
|
225
232
|
callback(finished, current)
|
|
226
233
|
if (transitionend && finished) {
|
|
227
|
-
runOnJS(
|
|
234
|
+
runOnJS(runOnJSCallback)('withTimingCallback', finished, current, duration)
|
|
228
235
|
}
|
|
229
236
|
})
|
|
230
237
|
: withTiming(value, { duration, easing })
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useEffect, useCallback, useMemo, useRef, ReactNode, ReactElement, isValidElement, useContext, useState, Dispatch, SetStateAction, Children, cloneElement, createElement } from 'react'
|
|
1
|
+
import { useEffect, useCallback, useMemo, useRef, ReactNode, ReactElement, isValidElement, useContext, useState, Dispatch, SetStateAction, Children, cloneElement, createElement, MutableRefObject } from 'react'
|
|
2
2
|
import { LayoutChangeEvent, TextStyle, ImageProps, Image } from 'react-native'
|
|
3
3
|
import { isObject, isFunction, isNumber, hasOwn, diffAndCloneA, error, warn } from '@mpxjs/utils'
|
|
4
4
|
import { VarContext, ScrollViewContext, RouteContext } from './context'
|
|
@@ -787,13 +787,11 @@ export function useHover ({ enableHover, hoverStartTime, hoverStayTime, disabled
|
|
|
787
787
|
const gesture = useMemo(() => {
|
|
788
788
|
return Gesture.Pan()
|
|
789
789
|
.onTouchesDown(() => {
|
|
790
|
-
|
|
791
|
-
runOnJS(setStartTimer)()
|
|
790
|
+
setStartTimer()
|
|
792
791
|
})
|
|
793
792
|
.onTouchesUp(() => {
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
})
|
|
793
|
+
setStayTimer()
|
|
794
|
+
}).runOnJS(true)
|
|
797
795
|
}, [])
|
|
798
796
|
|
|
799
797
|
if (gestureRef) {
|
|
@@ -805,3 +803,19 @@ export function useHover ({ enableHover, hoverStartTime, hoverStayTime, disabled
|
|
|
805
803
|
gesture
|
|
806
804
|
}
|
|
807
805
|
}
|
|
806
|
+
|
|
807
|
+
export function useRunOnJSCallback (callbackMapRef: MutableRefObject<Record<string, AnyFunc>>) {
|
|
808
|
+
const invokeCallback = useCallback((key: string, ...args: any) => {
|
|
809
|
+
const callback = callbackMapRef.current[key]
|
|
810
|
+
// eslint-disable-next-line node/no-callback-literal
|
|
811
|
+
if (isFunction(callback)) return callback(...args)
|
|
812
|
+
}, [])
|
|
813
|
+
|
|
814
|
+
useEffect(() => {
|
|
815
|
+
return () => {
|
|
816
|
+
callbackMapRef.current = {}
|
|
817
|
+
}
|
|
818
|
+
}, [])
|
|
819
|
+
|
|
820
|
+
return invokeCallback
|
|
821
|
+
}
|
|
@@ -49,7 +49,7 @@ import { processAppOption, getComponent } from ${stringifyRequest(loaderContext,
|
|
|
49
49
|
Vue.use(VueRouter)\n`
|
|
50
50
|
|
|
51
51
|
if (i18n) {
|
|
52
|
-
output += buildI18n({ i18n, loaderContext })
|
|
52
|
+
output += buildI18n({ i18n, isMain: true, loaderContext })
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
output += buildGlobalParams({
|
package/lib/web/processScript.js
CHANGED
|
@@ -7,7 +7,8 @@ const {
|
|
|
7
7
|
buildComponentsMap,
|
|
8
8
|
getRequireScript,
|
|
9
9
|
buildGlobalParams,
|
|
10
|
-
stringifyRequest
|
|
10
|
+
stringifyRequest,
|
|
11
|
+
buildI18n
|
|
11
12
|
} = require('./script-helper')
|
|
12
13
|
|
|
13
14
|
module.exports = function (script, {
|
|
@@ -24,7 +25,7 @@ module.exports = function (script, {
|
|
|
24
25
|
wxsModuleMap,
|
|
25
26
|
localComponentsMap
|
|
26
27
|
}, callback) {
|
|
27
|
-
const { projectRoot, appInfo, webConfig } = loaderContext.getMpx()
|
|
28
|
+
const { projectRoot, appInfo, webConfig, i18n } = loaderContext.getMpx()
|
|
28
29
|
|
|
29
30
|
let output = '/* script */\n'
|
|
30
31
|
|
|
@@ -70,6 +71,9 @@ module.exports = function (script, {
|
|
|
70
71
|
}
|
|
71
72
|
|
|
72
73
|
content += buildGlobalParams({ moduleId, scriptSrcMode, loaderContext, isProduction, webConfig, hasApp })
|
|
74
|
+
if (!hasApp && i18n) {
|
|
75
|
+
content += buildI18n({ i18n, loaderContext })
|
|
76
|
+
}
|
|
73
77
|
content += getRequireScript({ ctorType, script, loaderContext })
|
|
74
78
|
content += `
|
|
75
79
|
export default processComponentOption({
|
package/lib/web/script-helper.js
CHANGED
|
@@ -186,13 +186,17 @@ function buildGlobalParams ({
|
|
|
186
186
|
return content
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
-
function buildI18n ({ i18n, loaderContext }) {
|
|
189
|
+
function buildI18n ({ i18n, isMain, loaderContext }) {
|
|
190
190
|
let i18nContent = ''
|
|
191
191
|
const i18nObj = Object.assign({}, i18n)
|
|
192
|
-
|
|
193
|
-
|
|
192
|
+
if (!isMain) {
|
|
193
|
+
i18nContent += `import Vue from 'vue'
|
|
194
|
+
import Mpx from '@mpxjs/core'\n`
|
|
195
|
+
}
|
|
196
|
+
i18nContent += `import VueI18n from 'vue-i18n'
|
|
194
197
|
import { createI18n } from 'vue-i18n-bridge'
|
|
195
|
-
|
|
198
|
+
if (!Mpx.i18n) {
|
|
199
|
+
Vue.use(VueI18n , { bridge: true })\n`
|
|
196
200
|
const requestObj = {}
|
|
197
201
|
const i18nKeys = ['messages', 'dateTimeFormats', 'numberFormats']
|
|
198
202
|
i18nKeys.forEach((key) => {
|
|
@@ -201,15 +205,16 @@ function buildI18n ({ i18n, loaderContext }) {
|
|
|
201
205
|
delete i18nObj[`${key}Path`]
|
|
202
206
|
}
|
|
203
207
|
})
|
|
204
|
-
i18nContent += `
|
|
208
|
+
i18nContent += ` var i18nCfg = ${JSON.stringify(i18nObj)}\n`
|
|
205
209
|
Object.keys(requestObj).forEach((key) => {
|
|
206
|
-
i18nContent += `
|
|
210
|
+
i18nContent += ` i18nCfg.${key} = require(${requestObj[key]})\n`
|
|
207
211
|
})
|
|
208
212
|
i18nContent += `
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
+
i18nCfg.legacy = false
|
|
214
|
+
var i18n = createI18n(i18nCfg, VueI18n)
|
|
215
|
+
Vue.use(i18n)
|
|
216
|
+
Mpx.i18n = i18n
|
|
217
|
+
}\n`
|
|
213
218
|
return i18nContent
|
|
214
219
|
}
|
|
215
220
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mpxjs/webpack-plugin",
|
|
3
|
-
"version": "2.10.
|
|
3
|
+
"version": "2.10.13",
|
|
4
4
|
"description": "mpx compile core",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mpx"
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"@better-scroll/wheel": "^2.5.1",
|
|
29
29
|
"@better-scroll/zoom": "^2.5.1",
|
|
30
30
|
"@mpxjs/template-engine": "^2.8.7",
|
|
31
|
-
"@mpxjs/utils": "^2.10.
|
|
31
|
+
"@mpxjs/utils": "^2.10.13",
|
|
32
32
|
"acorn": "^8.11.3",
|
|
33
33
|
"acorn-walk": "^7.2.0",
|
|
34
34
|
"async": "^2.6.0",
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
},
|
|
84
84
|
"devDependencies": {
|
|
85
85
|
"@d11/react-native-fast-image": "^8.6.12",
|
|
86
|
-
"@mpxjs/api-proxy": "^2.10.
|
|
86
|
+
"@mpxjs/api-proxy": "^2.10.13",
|
|
87
87
|
"@types/babel-traverse": "^6.25.4",
|
|
88
88
|
"@types/babel-types": "^7.0.4",
|
|
89
89
|
"@types/react": "^18.2.79",
|
|
@@ -100,5 +100,5 @@
|
|
|
100
100
|
"engines": {
|
|
101
101
|
"node": ">=14.14.0"
|
|
102
102
|
},
|
|
103
|
-
"gitHead": "
|
|
103
|
+
"gitHead": "1b4a2d4765341ef6c6b74e501f72a0f856f247f9"
|
|
104
104
|
}
|