@mpxjs/core 2.10.13 → 2.10.15

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/@types/index.d.ts CHANGED
@@ -121,6 +121,7 @@ interface Context {
121
121
  createSelectorQuery: WechatMiniprogram.Component.InstanceMethods<Record<string, any>>['createSelectorQuery']
122
122
  createIntersectionObserver: WechatMiniprogram.Component.InstanceMethods<Record<string, any>>['createIntersectionObserver'],
123
123
  getPageId: WechatMiniprogram.Component.InstanceMethods<Record<string, any>>['getPageId']
124
+ getOpenerEventChannel: WechatMiniprogram.Component.InstanceMethods<Record<string, any>>['getOpenerEventChannel']
124
125
  }
125
126
  type ExtendedComponentOptions = {
126
127
  disconnectOnUnmounted?: boolean
@@ -274,7 +275,7 @@ export interface RnConfig {
274
275
  *
275
276
  * @param state 当前的导航状态对象
276
277
  */
277
- onStateChange?: (state: Record<string, any>) => void;
278
+ onStateChange?: (state: Record<string, any>) => void
278
279
 
279
280
  /**
280
281
  * 用于获取初始路由配置的函数。
@@ -286,7 +287,7 @@ export interface RnConfig {
286
287
  */
287
288
  parseAppProps?: (
288
289
  props: Record<string, any>
289
- ) => { initialRouteName?: string; initialParams?: any } | void;
290
+ ) => { initialRouteName?: string; initialParams?: any } | void
290
291
 
291
292
  /**
292
293
  * 页面栈长度为 1(即根页面)且用户尝试退出 App 时触发。
@@ -295,12 +296,12 @@ export interface RnConfig {
295
296
  * - `true`:允许退出应用
296
297
  * - `false`:阻止退出应用
297
298
  */
298
- onAppBack?: () => boolean;
299
+ onAppBack?: () => boolean
299
300
 
300
301
  /**
301
302
  * 是否禁用框架内部的 AppStateChange 监听。
302
303
  */
303
- disableAppStateListener?: boolean;
304
+ disableAppStateListener?: boolean
304
305
 
305
306
  /**
306
307
  * 控制首页回退按钮是否展示,并监听点击事件。
@@ -308,7 +309,7 @@ export interface RnConfig {
308
309
  * 如果绑定该函数,则首页显示返回按钮,点击后调用该函数作为回调。
309
310
  * 如需返回,请在函数内部手动调用 `back()`。
310
311
  */
311
- onStackTopBack?: () => void;
312
+ onStackTopBack?: () => void
312
313
 
313
314
  /**
314
315
  * 容器实现的 open-type 能力集合。
@@ -324,16 +325,26 @@ export interface RnConfig {
324
325
  * @returns `void`
325
326
  */
326
327
  onShareAppMessage?: (shareInfo: {
327
- title: string;
328
- path: string;
329
- imageUrl?: string;
330
- }) => void;
331
- };
328
+ title: string
329
+ path: string
330
+ imageUrl?: string
331
+ }) => void
332
+ }
332
333
 
333
334
  /**
334
335
  * 在使用 picker-view-column 时,触发短震动反馈。
335
336
  */
336
- pickerVibrate?: () => void;
337
+ onPickerVibrate?: () => void
338
+
339
+ /**
340
+ * 分包页面加载失败时触发
341
+ * @param subpackage 失败分包名
342
+ * @param errType 失败类型
343
+ */
344
+ onLazyLoadPageError?: (error: {
345
+ subpackage: string
346
+ errType: 'timeout' | 'fail'
347
+ }) => void
337
348
 
338
349
  /**
339
350
  * 自定义屏幕尺寸信息,用于 mpx style 渲染等依赖尺寸的功能。
@@ -343,7 +354,7 @@ export interface RnConfig {
343
354
  */
344
355
  customDimensions?: <T extends { window: ScaledSize; screen: ScaledSize }>(
345
356
  dimensions: T
346
- ) => T | void;
357
+ ) => T | void
347
358
 
348
359
  /**
349
360
  * 异步分包加载配置。
@@ -352,18 +363,18 @@ export interface RnConfig {
352
363
  /**
353
364
  * 加载超时时长配置,单位为毫秒。
354
365
  */
355
- timeout: number;
366
+ timeout: number
356
367
 
357
368
  /**
358
369
  * 异步分包页面加载超时或失败时,自定义兜底页面文件路径。
359
370
  */
360
- fallback: string;
371
+ fallback: string
361
372
 
362
373
  /**
363
374
  * 异步分包页面加载时,自定义 loading 页面文件路径。
364
375
  */
365
- loading: string;
366
- };
376
+ loading: string
377
+ }
367
378
 
368
379
  /**
369
380
  * 加载并执行异步分包的方法。
@@ -373,14 +384,14 @@ export interface RnConfig {
373
384
  * @param params.package 分包名
374
385
  * @returns Promise,表示加载完成
375
386
  */
376
- loadChunkAsync?: (params: { url: string; package: string }) => Promise<any>;
387
+ loadChunkAsync?: (params: { url: string; package: string }) => Promise<any>
377
388
 
378
389
  /**
379
390
  * 下载多个异步分包的方法(不执行)。
380
391
  *
381
392
  * @param packages 分包名数组
382
393
  */
383
- downloadChunkAsync?: (packages: Array<string>) => void;
394
+ downloadChunkAsync?: (packages: Array<string>) => void
384
395
  }
385
396
 
386
397
  interface MpxConfig {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mpxjs/core",
3
- "version": "2.10.13",
3
+ "version": "2.10.15",
4
4
  "description": "mpx runtime core",
5
5
  "keywords": [
6
6
  "miniprogram",
@@ -109,5 +109,5 @@
109
109
  "url": "https://github.com/didi/mpx/issues"
110
110
  },
111
111
  "sideEffects": false,
112
- "gitHead": "1b4a2d4765341ef6c6b74e501f72a0f856f247f9"
112
+ "gitHead": "4ea4a54f55aa938ad139e080827cffbbf7bb82db"
113
113
  }
package/src/core/proxy.js CHANGED
@@ -334,7 +334,8 @@ export default class MpxProxy {
334
334
  selectAllComponents: this.target.selectAllComponents.bind(this.target),
335
335
  createSelectorQuery: this.target.createSelectorQuery ? this.target.createSelectorQuery.bind(this.target) : envObj.createSelectorQuery.bind(envObj),
336
336
  createIntersectionObserver: this.target.createIntersectionObserver ? this.target.createIntersectionObserver.bind(this.target) : envObj.createIntersectionObserver.bind(envObj),
337
- getPageId: this.target.getPageId.bind(this.target)
337
+ getPageId: this.target.getPageId.bind(this.target),
338
+ getOpenerEventChannel: this.target.getOpenerEventChannel.bind(this.target)
338
339
  }
339
340
  ])
340
341
  if (!isObject(setupResult)) {
@@ -501,11 +502,19 @@ export default class MpxProxy {
501
502
  const hooks = this.hooks[hookName] || []
502
503
  let result
503
504
  if (isFunction(hook) && !hooksOnly) {
505
+ const setContext = hookName !== BEFORECREATE
506
+ if (setContext) {
507
+ setCurrentInstance(this)
508
+ }
504
509
  result = callWithErrorHandling(hook.bind(this.target), this, `${hookName} hook`, params)
510
+ if (setContext) {
511
+ unsetCurrentInstance()
512
+ }
505
513
  }
506
514
  hooks.forEach((hook) => {
507
515
  result = params ? hook(...params) : hook()
508
516
  })
517
+
509
518
  return result
510
519
  }
511
520
 
@@ -4,70 +4,85 @@ import contextMap from '../../dynamic/vnode/context'
4
4
 
5
5
  function logCallbackNotFound (context, callbackName) {
6
6
  const location = context.__mpxProxy && context.__mpxProxy.options.mpxFileResource
7
- error(`Instance property [${callbackName}] is not function, please check.`, location)
7
+ error(
8
+ `Instance property [${callbackName}] is not function, please check.`,
9
+ location
10
+ )
11
+ }
12
+
13
+ function handleEvent (context, $event, isCapture) {
14
+ if (typeof Mpx.config.proxyEventHandler === 'function') {
15
+ try {
16
+ Mpx.config.proxyEventHandler($event, context)
17
+ } catch (e) {
18
+ }
19
+ }
20
+ const location = context.__mpxProxy.options.mpxFileResource
21
+ const type = $event.type
22
+ // thanos 平台特殊事件标识
23
+ const emitMode = $event.detail && $event.detail.mpxEmit
24
+ if (!type) {
25
+ error('Event object must have [type] property!', location)
26
+ return
27
+ }
28
+ let fallbackType = ''
29
+ if (type === 'begin' || type === 'end') {
30
+ // 地图的 regionchange 事件会派发 e.type 为 begin 和 end 的事件
31
+ fallbackType = __mpx_mode__ === 'ali' ? 'regionChange' : 'regionchange'
32
+ } else if (/-([a-z])/.test(type)) {
33
+ fallbackType = dash2hump(type)
34
+ } else if (__mpx_mode__ === 'ali') {
35
+ fallbackType = type.replace(/^./, i => i.toLowerCase())
36
+ }
37
+ const target = $event.currentTarget || $event.target
38
+ if (!target) {
39
+ error(`[${type}] event object must have [currentTarget/target] property!`, location)
40
+ return
41
+ }
42
+ const mode = isCapture ? 'capture' : 'bubble'
43
+ const eventConfigs = target.dataset.eventconfigs?.[mode] || {}
44
+
45
+ const curEventConfig = eventConfigs[type] || eventConfigs[fallbackType] || []
46
+ // 如果有 mpxuid 说明是运行时组件,那么需要设置对应的上下文
47
+ const rootRuntimeContext = contextMap.get(target.dataset.mpxuid)
48
+ const runtimeContext = rootRuntimeContext || context
49
+ let returnedValue
50
+ curEventConfig.forEach((item) => {
51
+ const callbackName = item[0]
52
+ if (emitMode) {
53
+ // thanos 平台特殊事件标识处理
54
+ $event = $event.detail.data
55
+ }
56
+ if (callbackName) {
57
+ const params = item.length > 1
58
+ ? item.slice(1).map(item => {
59
+ if (item === '__mpx_event__') {
60
+ return $event
61
+ } else {
62
+ return item
63
+ }
64
+ })
65
+ : [$event]
66
+ if (typeof runtimeContext[callbackName] === 'function') {
67
+ returnedValue = runtimeContext[callbackName].apply(
68
+ runtimeContext,
69
+ params
70
+ )
71
+ } else {
72
+ logCallbackNotFound(runtimeContext, callbackName)
73
+ }
74
+ }
75
+ })
76
+ return returnedValue
8
77
  }
9
78
 
10
79
  export default function proxyEventMixin () {
11
80
  const methods = {
12
81
  __invoke ($event) {
13
- if (typeof Mpx.config.proxyEventHandler === 'function') {
14
- try {
15
- Mpx.config.proxyEventHandler($event, this)
16
- } catch (e) {
17
- }
18
- }
19
- const location = this.__mpxProxy.options.mpxFileResource
20
- const type = $event.type
21
- // thanos 平台特殊事件标识
22
- const emitMode = $event.detail && $event.detail.mpxEmit
23
- if (!type) {
24
- error('Event object must have [type] property!', location)
25
- return
26
- }
27
- let fallbackType = ''
28
- if (type === 'begin' || type === 'end') {
29
- // 地图的 regionchange 事件会派发 e.type 为 begin 和 end 的事件
30
- fallbackType = __mpx_mode__ === 'ali' ? 'regionChange' : 'regionchange'
31
- } else if (/-([a-z])/.test(type)) {
32
- fallbackType = dash2hump(type)
33
- } else if (__mpx_mode__ === 'ali') {
34
- fallbackType = type.replace(/^./, i => i.toLowerCase())
35
- }
36
- const target = $event.currentTarget || $event.target
37
- if (!target) {
38
- error(`[${type}] event object must have [currentTarget/target] property!`, location)
39
- return
40
- }
41
- const eventConfigs = target.dataset.eventconfigs || {}
42
- const curEventConfig = eventConfigs[type] || eventConfigs[fallbackType] || []
43
- // 如果有 mpxuid 说明是运行时组件,那么需要设置对应的上下文
44
- const rootRuntimeContext = contextMap.get(target.dataset.mpxuid)
45
- const context = rootRuntimeContext || this
46
- let returnedValue
47
- curEventConfig.forEach((item) => {
48
- const callbackName = item[0]
49
- if (emitMode) {
50
- // thanos 平台特殊事件标识处理
51
- $event = $event.detail.data
52
- }
53
- if (callbackName) {
54
- const params = item.length > 1
55
- ? item.slice(1).map(item => {
56
- if (item === '__mpx_event__') {
57
- return $event
58
- } else {
59
- return item
60
- }
61
- })
62
- : [$event]
63
- if (typeof context[callbackName] === 'function') {
64
- returnedValue = context[callbackName].apply(context, params)
65
- } else {
66
- logCallbackNotFound(context, callbackName)
67
- }
68
- }
69
- })
70
- return returnedValue
82
+ return handleEvent(this, $event, false)
83
+ },
84
+ __captureInvoke ($event) {
85
+ return handleEvent(this, $event, true)
71
86
  },
72
87
  __model (expr, $event, valuePath = ['value'], filterMethod) {
73
88
  const innerFilter = {
@@ -1,4 +1,4 @@
1
- import { isObject, isArray, dash2hump, cached, isEmptyObject } from '@mpxjs/utils'
1
+ import { isObject, isArray, dash2hump, cached, isEmptyObject, hasOwn } from '@mpxjs/utils'
2
2
  import { Dimensions, StyleSheet } from 'react-native'
3
3
  import Mpx from '../../index'
4
4
 
@@ -176,6 +176,14 @@ function transformStyleObj (styleObj) {
176
176
  return transformed
177
177
  }
178
178
 
179
+ function isNativeStyle (style) {
180
+ return Array.isArray(style) || (
181
+ typeof style === 'object' &&
182
+ // Reanimated 的 animated style 通常会包含 viewDescriptors 或 _animations
183
+ (hasOwn(style, 'viewDescriptors') || hasOwn(style, '_animations'))
184
+ )
185
+ }
186
+
179
187
  export default function styleHelperMixin () {
180
188
  return {
181
189
  methods: {
@@ -183,7 +191,10 @@ export default function styleHelperMixin () {
183
191
  return concat(staticClass, stringifyDynamicClass(dynamicClass))
184
192
  },
185
193
  __getStyle (staticClass, dynamicClass, staticStyle, dynamicStyle, hide) {
186
- const result = {}
194
+ const isNativeStaticStyle = staticStyle && isNativeStyle(staticStyle)
195
+ let result = isNativeStaticStyle ? [] : {}
196
+ const mergeResult = isNativeStaticStyle ? (o) => result.push(o) : (o) => Object.assign(result, o)
197
+
187
198
  const classMap = this.__getClassMap?.() || {}
188
199
  const appClassMap = global.__getAppClassMap?.() || {}
189
200
 
@@ -192,24 +203,34 @@ export default function styleHelperMixin () {
192
203
  const classString = mpEscape(concat(staticClass, stringifyDynamicClass(dynamicClass)))
193
204
  classString.split(/\s+/).forEach((className) => {
194
205
  if (classMap[className]) {
195
- Object.assign(result, classMap[className])
206
+ mergeResult(classMap[className])
196
207
  } else if (appClassMap[className]) {
197
208
  // todo 全局样式在每个页面和组件中生效,以支持全局原子类,后续支持样式模块复用后可考虑移除
198
- Object.assign(result, appClassMap[className])
209
+ mergeResult(appClassMap[className])
199
210
  } else if (isObject(this.__props[className])) {
200
211
  // externalClasses必定以对象形式传递下来
201
- Object.assign(result, this.__props[className])
212
+ mergeResult(this.__props[className])
202
213
  }
203
214
  })
204
215
  }
205
216
 
206
217
  if (staticStyle || dynamicStyle) {
207
- const styleObj = Object.assign({}, parseStyleText(staticStyle), normalizeDynamicStyle(dynamicStyle))
208
- Object.assign(result, transformStyleObj(styleObj))
218
+ const styleObj = {}
219
+ if (isNativeStaticStyle) {
220
+ if (Array.isArray(staticStyle)) {
221
+ result = result.concat(staticStyle)
222
+ } else {
223
+ mergeResult(staticStyle)
224
+ }
225
+ } else {
226
+ Object.assign(styleObj, parseStyleText(staticStyle))
227
+ }
228
+ Object.assign(styleObj, normalizeDynamicStyle(dynamicStyle))
229
+ mergeResult(transformStyleObj(styleObj))
209
230
  }
210
231
 
211
232
  if (hide) {
212
- Object.assign(result, {
233
+ mergeResult({
213
234
  // display: 'none'
214
235
  // RN下display:'none'容易引发未知异常问题,使用布局样式模拟
215
236
  flex: 0,
@@ -220,8 +241,8 @@ export default function styleHelperMixin () {
220
241
  overflow: 'hidden'
221
242
  })
222
243
  }
223
-
224
- return isEmptyObject(result) ? empty : result
244
+ const isEmpty = isNativeStaticStyle ? result.length > 0 : isEmptyObject(result)
245
+ return isEmpty ? empty : result
225
246
  }
226
247
  }
227
248
  }