@mpxjs/core 2.9.66 → 2.9.67

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.
@@ -4,6 +4,8 @@ declare let __mpx_mode__: 'wx' | 'ali' | 'swan' | 'qq' | 'tt' | 'web' | 'dd' | '
4
4
  // declaration for mpx env
5
5
  declare let __mpx_env__: string
6
6
 
7
+ declare const Mixin: WechatMiniprogram.Behavior.Constructor
8
+
7
9
  // Wildcard module declarations for ?resolve case
8
10
  declare module '*?resolve' {
9
11
  const resourcePath: string
package/@types/index.d.ts CHANGED
@@ -137,6 +137,11 @@ interface ComponentOpt<D extends Data, P extends Properties, C, M extends Method
137
137
 
138
138
  initData?: Record<string, any>
139
139
 
140
+ provide?: Record<string, any> | (() => Record<string, any>)
141
+ inject?:
142
+ | { [key: string]: string | Symbol | { from?: string | Symbol; default?: any } }
143
+ | Array<string>
144
+
140
145
  [index: string]: any
141
146
  }
142
147
 
@@ -259,13 +264,15 @@ interface MpxConfig {
259
264
  ignoreWarning: boolean | string | RegExp | ((msg: string, location: string, e: Error) => boolean)
260
265
  ignoreProxyWhiteList: Array<string>
261
266
  observeClassInstance: boolean | Array<AnyConstructor>
262
- errorHandler: (e: Error, target: ComponentIns<{}, {}, {}, {}, []>, hookName: string) => any | null
267
+ errorHandler: (msg: String, location: String, e: Error) => any | null
268
+ warnHandler: (msg: String, location: String, e: Error) => any | null
263
269
  proxyEventHandler: (e: WechatMiniprogram.CustomEvent) => any | null
264
270
  setDataHandler: (data: object, target: ComponentIns<{}, {}, {}, {}, []>) => any | null
265
271
  forceFlushSync: boolean,
266
272
  webRouteConfig: object,
267
273
  webConfig: object,
268
- webviewConfig?: WebviewConfig
274
+ webviewConfig: WebviewConfig,
275
+ rnConfig: object,
269
276
  }
270
277
 
271
278
  type SupportedMode = 'wx' | 'ali' | 'qq' | 'swan' | 'tt' | 'web' | 'qa'
@@ -306,6 +313,8 @@ export interface Mpx {
306
313
 
307
314
  delete: typeof del
308
315
 
316
+ provide: typeof provide
317
+
309
318
  config: MpxConfig
310
319
 
311
320
  i18n: {
@@ -570,6 +579,13 @@ export function onScopeDispose (fn: () => void): void
570
579
  export function set<T extends object> (target: T, key: string | number, value: any): void
571
580
  export function del<T extends object> (target: T, key: keyof T): void
572
581
 
582
+ // provide & inject
583
+ export declare function provide<T>(key: InjectionKey<T> | string | number, value: T): void;
584
+ export declare function inject<T>(key: InjectionKey<T> | string): T | undefined;
585
+ export declare function inject<T>(key: InjectionKey<T> | string, defaultValue: T, treatDefaultAsFactory?: false): T;
586
+ export declare function inject<T>(key: InjectionKey<T> | string, defaultValue: T | (() => T), treatDefaultAsFactory: true): T;
587
+ export declare interface InjectionKey<T> extends Symbol {}
588
+
573
589
  // nextTick
574
590
  export function nextTick (fn: () => any): void
575
591
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mpxjs/core",
3
- "version": "2.9.66",
3
+ "version": "2.9.67",
4
4
  "description": "mpx runtime core",
5
5
  "keywords": [
6
6
  "miniprogram",
@@ -19,7 +19,7 @@
19
19
  ],
20
20
  "main": "src/index.js",
21
21
  "dependencies": {
22
- "@mpxjs/utils": "^2.9.65",
22
+ "@mpxjs/utils": "^2.9.67",
23
23
  "lodash": "^4.1.1",
24
24
  "miniprogram-api-typings": "^3.10.0"
25
25
  },
@@ -97,5 +97,5 @@
97
97
  "url": "https://github.com/didi/mpx/issues"
98
98
  },
99
99
  "sideEffects": false,
100
- "gitHead": "ff9eb06a3be28538870823cebf813ed56f39bbd7"
100
+ "gitHead": "b23d3850c16543c5998811b8d1d8e6ee7988c0f8"
101
101
  }
@@ -354,7 +354,7 @@ function transformHOOKS (options) {
354
354
  const componentHooksMap = makeMap(convertRule.lifecycle.component)
355
355
  for (const key in options) {
356
356
  // 使用Component创建page实例,页面专属生命周期&自定义方法需写在methods内部
357
- if (typeof options[key] === 'function' && key !== 'dataFn' && key !== 'setup' && !componentHooksMap[key]) {
357
+ if (typeof options[key] === 'function' && key !== 'dataFn' && key !== 'setup' && key !== 'provide' && !componentHooksMap[key]) {
358
358
  if (!options.methods) options.methods = {}
359
359
  options.methods[key] = options[key]
360
360
  delete options[key]
package/src/core/proxy.js CHANGED
@@ -8,10 +8,12 @@ import Mpx from '../index'
8
8
  import {
9
9
  noop,
10
10
  type,
11
+ isArray,
11
12
  isFunction,
12
13
  isObject,
13
14
  isEmptyObject,
14
15
  isPlainObject,
16
+ isWeb,
15
17
  doGetByPath,
16
18
  getByPath,
17
19
  setByPath,
@@ -25,6 +27,7 @@ import {
25
27
  processUndefined,
26
28
  getFirstKey,
27
29
  callWithErrorHandling,
30
+ wrapMethodsWithErrorHandling,
28
31
  warn,
29
32
  error,
30
33
  getEnvObj
@@ -47,6 +50,7 @@ import {
47
50
  } from './innerLifecycle'
48
51
  import contextMap from '../dynamic/vnode/context'
49
52
  import { getAst } from '../dynamic/astCache'
53
+ import { inject, provide } from '../platform/export/apiInject'
50
54
 
51
55
  let uid = 0
52
56
 
@@ -160,11 +164,15 @@ export default class MpxProxy {
160
164
  // web中BEFORECREATE钩子通过vue的beforeCreate钩子单独驱动
161
165
  this.callHook(BEFORECREATE)
162
166
  setCurrentInstance(this)
167
+ // 在 props/data 初始化之前初始化 inject
168
+ this.initInject()
163
169
  this.initProps()
164
170
  this.initSetup()
165
171
  this.initData()
166
172
  this.initComputed()
167
173
  this.initWatch()
174
+ // 在 props/data 初始化之后初始化 provide
175
+ this.initProvide()
168
176
  unsetCurrentInstance()
169
177
  }
170
178
 
@@ -219,6 +227,16 @@ export default class MpxProxy {
219
227
  // 页面/组件销毁清除上下文的缓存
220
228
  contextMap.remove(this.uid)
221
229
  }
230
+ if (!isWeb && this.options.__type__ === 'page') {
231
+ // 小程序页面销毁时移除对应的 provide
232
+ if (isFunction(this.target.getPageId)) {
233
+ const pageId = this.target.getPageId()
234
+ const providesMap = global.__mpxProvidesMap
235
+ if (providesMap.__pages[pageId]) {
236
+ delete providesMap.__pages[pageId]
237
+ }
238
+ }
239
+ }
222
240
  this.callHook(BEFOREUNMOUNT)
223
241
  this.scope?.stop()
224
242
  if (this.update) this.update.active = false
@@ -277,7 +295,7 @@ export default class MpxProxy {
277
295
  initSetup () {
278
296
  const setup = this.options.setup
279
297
  if (setup) {
280
- const setupResult = callWithErrorHandling(setup, this, 'setup function', [
298
+ let setupResult = callWithErrorHandling(setup, this, 'setup function', [
281
299
  this.props,
282
300
  {
283
301
  triggerEvent: this.target.triggerEvent ? this.target.triggerEvent.bind(this.target) : noop,
@@ -294,6 +312,7 @@ export default class MpxProxy {
294
312
  error(`Setup() should return a object, received: ${type(setupResult)}.`, this.options.mpxFileResource)
295
313
  return
296
314
  }
315
+ setupResult = wrapMethodsWithErrorHandling(setupResult, this)
297
316
  proxy(this.target, setupResult, undefined, false, this.createProxyConflictHandler('setup result'))
298
317
  this.collectLocalKeys(setupResult, (key, val) => !isFunction(val))
299
318
  }
@@ -350,6 +369,55 @@ export default class MpxProxy {
350
369
  }
351
370
  }
352
371
 
372
+ initProvide () {
373
+ const provideOpt = this.options.provide
374
+ if (provideOpt) {
375
+ const provided = isFunction(provideOpt)
376
+ ? callWithErrorHandling(provideOpt.bind(this.target), this, 'provide function')
377
+ : provideOpt
378
+ if (!isObject(provided)) {
379
+ return
380
+ }
381
+ Object.keys(provided).forEach(key => {
382
+ provide(key, provided[key])
383
+ })
384
+ }
385
+ }
386
+
387
+ initInject () {
388
+ const injectOpt = this.options.inject
389
+ if (injectOpt) {
390
+ this.resolveInject(injectOpt)
391
+ }
392
+ }
393
+
394
+ resolveInject (injectOpt) {
395
+ if (isArray(injectOpt)) {
396
+ const normalized = {}
397
+ for (let i = 0; i < injectOpt.length; i++) {
398
+ normalized[injectOpt[i]] = injectOpt[i]
399
+ }
400
+ injectOpt = normalized
401
+ }
402
+ const injectObj = {}
403
+ for (const key in injectOpt) {
404
+ const opt = injectOpt[key]
405
+ let injected
406
+ if (isObject(opt)) {
407
+ if ('default' in opt) {
408
+ injected = inject(opt.from || key, opt.default, true)
409
+ } else {
410
+ injected = inject(opt.from || key)
411
+ }
412
+ } else {
413
+ injected = inject(opt)
414
+ }
415
+ injectObj[key] = injected
416
+ }
417
+ proxy(this.target, injectObj, undefined, false, this.createProxyConflictHandler('inject'))
418
+ this.collectLocalKeys(injectObj)
419
+ }
420
+
353
421
  watch (source, cb, options) {
354
422
  const target = this.target
355
423
  const getter = isString(source)
@@ -1,6 +1,6 @@
1
1
  import transferOptions from '../core/transferOptions'
2
2
  import builtInKeysMap from './patch/builtInKeysMap'
3
- import { makeMap, spreadProp } from '@mpxjs/utils'
3
+ import { makeMap, spreadProp, parseUrlQuery } from '@mpxjs/utils'
4
4
  import { mergeLifecycle } from '../convertor/mergeLifecycle'
5
5
  import * as wxLifecycle from '../platform/patch/wx/lifecycle'
6
6
  import Mpx from '../index'
@@ -40,7 +40,7 @@ function createAppInstance (appData) {
40
40
  export default function createApp (option, config = {}) {
41
41
  const appData = {}
42
42
 
43
- const { NavigationContainer, createNavigationContainerRef, createNativeStackNavigator, SafeAreaProvider } = global.__navigationHelper
43
+ const { NavigationContainer, createStackNavigator, SafeAreaProvider } = global.__navigationHelper
44
44
  // app选项目前不需要进行转换
45
45
  const { rawOptions, currentInject } = transferOptions(option, 'app', false)
46
46
  const defaultOptions = filterOptions(spreadProp(rawOptions, 'methods'), appData)
@@ -51,16 +51,25 @@ export default function createApp (option, config = {}) {
51
51
  }
52
52
  const pages = currentInject.getPages() || {}
53
53
  const firstPage = currentInject.firstPage
54
- const Stack = createNativeStackNavigator()
55
- const navigationRef = createNavigationContainerRef()
56
- const pageScreens = Object.entries(pages).map(([key, item]) => {
57
- return createElement(Stack.Screen, {
58
- name: key,
59
- component: item
54
+ const Stack = createStackNavigator()
55
+ const getPageScreens = (initialRouteName, initialParams) => {
56
+ return Object.entries(pages).map(([key, item]) => {
57
+ if (key === initialRouteName) {
58
+ return createElement(Stack.Screen, {
59
+ name: key,
60
+ component: item,
61
+ initialParams
62
+ })
63
+ }
64
+ return createElement(Stack.Screen, {
65
+ name: key,
66
+ component: item
67
+ })
60
68
  })
61
- })
69
+ }
62
70
  global.__mpxOptionsMap = global.__mpxOptionsMap || {}
63
- const onStateChange = () => {
71
+ const onStateChange = (state) => {
72
+ Mpx.config.rnConfig.onStateChange?.(state)
64
73
  if (global.__navigationHelper.lastSuccessCallback) {
65
74
  global.__navigationHelper.lastSuccessCallback()
66
75
  global.__navigationHelper.lastSuccessCallback = null
@@ -81,26 +90,48 @@ export default function createApp (option, config = {}) {
81
90
  error: []
82
91
  }
83
92
 
93
+ global.__mpxAppLaunched = false
94
+
84
95
  global.__mpxAppFocusedState = ref('show')
85
- global.__mpxOptionsMap[currentInject.moduleId] = memo(() => {
96
+ global.__mpxOptionsMap[currentInject.moduleId] = memo((props) => {
86
97
  const instanceRef = useRef(null)
87
98
  if (!instanceRef.current) {
88
99
  instanceRef.current = createAppInstance(appData)
89
100
  }
90
101
  const instance = instanceRef.current
91
- useEffect(() => {
92
- const current = navigationRef.isReady() ? navigationRef.getCurrentRoute() : {}
93
- const options = {
94
- path: current.name,
95
- query: current.params,
96
- scene: 0,
97
- shareTicket: '',
98
- referrerInfo: {}
102
+ const initialRouteRef = useRef({
103
+ initialRouteName: firstPage,
104
+ initialParams: {}
105
+ })
106
+
107
+ if (!global.__mpxAppLaunched) {
108
+ const parsed = Mpx.config.rnConfig.parseAppProps?.(props) || {}
109
+ if (parsed.url) {
110
+ const { path, queryObj } = parseUrlQuery(parsed.url)
111
+ Object.assign(initialRouteRef.current, {
112
+ initialRouteName: path.startsWith('/') ? path.slice(1) : path,
113
+ initialParams: queryObj
114
+ })
115
+ }
116
+ global.__mpxAppOnLaunch = (navigation) => {
117
+ global.__mpxAppLaunched = true
118
+ const state = navigation.getState()
119
+ Mpx.config.rnConfig.onStateChange?.(state)
120
+ const current = state.routes[state.index]
121
+ global.__mpxEnterOptions = {
122
+ path: current.name,
123
+ query: current.params,
124
+ scene: 0,
125
+ shareTicket: '',
126
+ referrerInfo: {}
127
+ }
128
+ defaultOptions.onLaunch && defaultOptions.onLaunch.call(instance, global.__mpxEnterOptions)
129
+ defaultOptions.onShow && defaultOptions.onShow.call(instance, global.__mpxEnterOptions)
99
130
  }
100
- global.__mpxEnterOptions = options
101
- defaultOptions.onLaunch && defaultOptions.onLaunch.call(instance, options)
131
+ }
132
+
133
+ useEffect(() => {
102
134
  if (defaultOptions.onShow) {
103
- defaultOptions.onShow.call(instance, options)
104
135
  global.__mpxAppCbs.show.push(defaultOptions.onShow.bind(instance))
105
136
  }
106
137
  if (defaultOptions.onHide) {
@@ -113,7 +144,7 @@ export default function createApp (option, config = {}) {
113
144
  const changeSubscription = ReactNative.AppState.addEventListener('change', (currentState) => {
114
145
  if (currentState === 'active') {
115
146
  global.__mpxAppCbs.show.forEach((cb) => {
116
- cb(options)
147
+ cb(global.__mpxEnterOptions)
117
148
  })
118
149
  global.__mpxAppFocusedState.value = 'show'
119
150
  } else if (currentState === 'inactive') {
@@ -138,19 +169,22 @@ export default function createApp (option, config = {}) {
138
169
  }
139
170
  }, [])
140
171
 
172
+ const { initialRouteName, initialParams } = initialRouteRef.current
141
173
  return createElement(SafeAreaProvider,
142
174
  null,
143
175
  createElement(NavigationContainer,
144
176
  {
145
- ref: navigationRef,
146
177
  onStateChange,
147
178
  onUnhandledAction
148
179
  },
149
180
  createElement(Stack.Navigator,
150
181
  {
151
- initialRouteName: firstPage
182
+ initialRouteName,
183
+ headerBackButtonDisplayMode: 'minimal',
184
+ headerMode: 'float',
185
+ gestureEnabled: true
152
186
  },
153
- ...pageScreens
187
+ ...getPageScreens(initialRouteName, initialParams)
154
188
  )
155
189
  )
156
190
  )
@@ -5,6 +5,7 @@ import { makeMap, spreadProp, isBrowser } from '@mpxjs/utils'
5
5
  import { mergeLifecycle } from '../convertor/mergeLifecycle'
6
6
  import * as webLifecycle from '../platform/patch/web/lifecycle'
7
7
  import Mpx from '../index'
8
+ import { initAppProvides } from './export/apiInject'
8
9
 
9
10
  const webAppHooksMap = makeMap(mergeLifecycle(webLifecycle.LIFECYCLE).app)
10
11
 
@@ -14,7 +15,7 @@ function filterOptions (options, appData) {
14
15
  if (builtInKeysMap[key]) {
15
16
  return
16
17
  }
17
- if (__mpx_mode__ === 'web' && !webAppHooksMap[key]) {
18
+ if (__mpx_mode__ === 'web' && !webAppHooksMap[key] && key !== 'provide') {
18
19
  appData[key] = options[key]
19
20
  } else {
20
21
  newOptions[key] = options[key]
@@ -87,6 +88,7 @@ export default function createApp (option, config = {}) {
87
88
  return appData
88
89
  }
89
90
  } else {
91
+ initAppProvides(rawOptions)
90
92
  defaultOptions.onAppInit && defaultOptions.onAppInit()
91
93
  const ctor = config.customCtor || global.currentCtor || App
92
94
  ctor(defaultOptions)
@@ -0,0 +1,68 @@
1
+ import { callWithErrorHandling, isFunction, isObject, warn } from '@mpxjs/utils'
2
+ import { currentInstance } from '../../core/proxy'
3
+
4
+ const providesMap = {
5
+ /** 全局 scope */
6
+ __app: Object.create(null),
7
+ /** 页面 scope */
8
+ __pages: Object.create(null)
9
+ }
10
+
11
+ global.__mpxProvidesMap = providesMap
12
+
13
+ /** @internal createApp() 初始化应用层 scope provide */
14
+ export function initAppProvides (appOptions) {
15
+ const provideOpt = appOptions.provide
16
+ if (provideOpt) {
17
+ const provided = isFunction(provideOpt)
18
+ ? callWithErrorHandling(provideOpt.bind(appOptions), appOptions, 'createApp provide function')
19
+ : provideOpt
20
+ if (isObject(provided)) {
21
+ providesMap.__app = provided
22
+ } else {
23
+ warn('App provides must be an object or a function that returns an object.')
24
+ }
25
+ }
26
+ }
27
+
28
+ function resolvePageId (context) {
29
+ if (context && isFunction(context.getPageId)) {
30
+ return context.getPageId()
31
+ }
32
+ }
33
+
34
+ function resolvePageProvides (context) {
35
+ const pageId = resolvePageId(context)
36
+ return providesMap.__pages[pageId] || (providesMap.__pages[pageId] = Object.create(null))
37
+ }
38
+
39
+ export function provide (key, value) {
40
+ const instance = currentInstance
41
+ if (!instance) {
42
+ warn('provide() can only be used inside setup().')
43
+ return
44
+ }
45
+ // 小程序无法实现组件父级引用,所以 provide scope 设置为组件所在页面
46
+ const provides = resolvePageProvides(instance.target)
47
+ provides[key] = value
48
+ }
49
+
50
+ export function inject (key, defaultValue, treatDefaultAsFactory = false) {
51
+ const instance = currentInstance
52
+ if (!instance) {
53
+ warn('inject() can only be used inside setup()')
54
+ return
55
+ }
56
+ const provides = resolvePageProvides(instance.target)
57
+ if (key in provides) {
58
+ return provides[key]
59
+ } else if (key in providesMap.__app) {
60
+ return providesMap.__app[key]
61
+ } else if (arguments.length > 1) {
62
+ return treatDefaultAsFactory && isFunction(defaultValue)
63
+ ? defaultValue.call(instance && instance.target)
64
+ : defaultValue
65
+ } else {
66
+ warn(`injection "${String(key)}" not found.`)
67
+ }
68
+ }
@@ -0,0 +1 @@
1
+ export { provide, inject } from 'vue'
@@ -42,3 +42,8 @@ export {
42
42
  export {
43
43
  useI18n
44
44
  } from '../../platform/builtInMixins/i18nMixin'
45
+
46
+ export {
47
+ provide,
48
+ inject
49
+ } from './apiInject'
@@ -27,7 +27,9 @@ export {
27
27
  // effectScope
28
28
  effectScope,
29
29
  getCurrentScope,
30
- onScopeDispose
30
+ onScopeDispose,
31
+ provide,
32
+ inject
31
33
  } from 'vue'
32
34
 
33
35
  export {
@@ -1,7 +1,7 @@
1
1
  import MpxProxy from '../../../core/proxy'
2
2
  import builtInKeysMap from '../builtInKeysMap'
3
3
  import mergeOptions from '../../../core/mergeOptions'
4
- import { error, diffAndCloneA, hasOwn, noop } from '@mpxjs/utils'
4
+ import { error, diffAndCloneA, hasOwn, noop, wrapMethodsWithErrorHandling } from '@mpxjs/utils'
5
5
 
6
6
  function transformApiForProxy (context, currentInject) {
7
7
  const rawSetData = context.setData.bind(context)
@@ -100,12 +100,25 @@ function filterOptions (options, type) {
100
100
  if (!hasOwn(newOptions, 'props')) {
101
101
  newOptions.props = Object.assign({}, options.props, options.properties)
102
102
  }
103
- } else if (key === 'methods' && type === 'page') {
104
- Object.assign(newOptions, options[key])
103
+ } else if (key === 'methods') {
104
+ const newMethods = wrapMethodsWithErrorHandling(options[key])
105
+ if (type === 'page') {
106
+ // 构造器为Page时抽取所有methods方法到顶层
107
+ Object.assign(newOptions, newMethods)
108
+ } else {
109
+ newOptions[key] = newMethods
110
+ }
111
+ } else if (key === 'behaviors') {
112
+ newOptions.mixins = options[key]
105
113
  } else {
106
114
  newOptions[key] = options[key]
107
115
  }
108
116
  })
117
+ if (newOptions.relations) {
118
+ // ali relations 需要设置 options.relations = true
119
+ newOptions.options = newOptions.options || {}
120
+ newOptions.options.relations = true
121
+ }
109
122
  return newOptions
110
123
  }
111
124
 
@@ -24,6 +24,8 @@ if (__mpx_mode__ === 'web') {
24
24
  'initData',
25
25
  'watch',
26
26
  'computed',
27
+ 'provide',
28
+ 'inject',
27
29
  'mpxCustomKeysForBlend',
28
30
  'mpxConvertMode',
29
31
  'mpxFileResource',
@@ -3,7 +3,7 @@ import * as ReactNative from 'react-native'
3
3
  import { ReactiveEffect } from '../../../observer/effect'
4
4
  import { watch } from '../../../observer/watch'
5
5
  import { reactive, set, del } from '../../../observer/reactive'
6
- import { hasOwn, isFunction, noop, isObject, getByPath, collectDataset, hump2dash } from '@mpxjs/utils'
6
+ import { hasOwn, isFunction, noop, isObject, getByPath, collectDataset, hump2dash, wrapMethodsWithErrorHandling } from '@mpxjs/utils'
7
7
  import MpxProxy from '../../../core/proxy'
8
8
  import { BEFOREUPDATE, ONLOAD, UPDATED, ONSHOW, ONHIDE, ONRESIZE, REACTHOOKSEXEC } from '../../../core/innerLifecycle'
9
9
  import mergeOptions from '../../../core/mergeOptions'
@@ -347,6 +347,7 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
347
347
  rawOptions = mergeOptions(rawOptions, type, false)
348
348
  const components = Object.assign({}, rawOptions.components, currentInject.getComponents())
349
349
  const validProps = Object.assign({}, rawOptions.props, rawOptions.properties)
350
+ if (rawOptions.methods) rawOptions.methods = wrapMethodsWithErrorHandling(rawOptions.methods)
350
351
  const defaultOptions = memo(forwardRef((props, ref) => {
351
352
  const instanceRef = useRef(null)
352
353
  const propsRef = useRef(null)
@@ -365,7 +366,21 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
365
366
 
366
367
  const proxy = instance.__mpxProxy
367
368
 
368
- proxy.callHook(REACTHOOKSEXEC)
369
+ let hooksResult = proxy.callHook(REACTHOOKSEXEC, [props])
370
+ if (isObject(hooksResult)) {
371
+ hooksResult = wrapMethodsWithErrorHandling(hooksResult, proxy)
372
+ if (isFirst) {
373
+ const onConflict = proxy.createProxyConflictHandler('react hooks result')
374
+ Object.keys(hooksResult).forEach((key) => {
375
+ if (key in proxy.target) {
376
+ onConflict(key)
377
+ }
378
+ proxy.target[key] = hooksResult[key]
379
+ })
380
+ } else {
381
+ Object.assign(proxy.target, hooksResult)
382
+ }
383
+ }
369
384
 
370
385
  useEffect(() => {
371
386
  if (!isFirst) {
@@ -391,6 +406,9 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
391
406
 
392
407
  useEffect(() => {
393
408
  if (type === 'page') {
409
+ if (!global.__mpxAppLaunched && global.__mpxAppOnLaunch) {
410
+ global.__mpxAppOnLaunch(props.navigation)
411
+ }
394
412
  proxy.callHook(ONLOAD, [props.route.params || {}])
395
413
  }
396
414
  proxy.mounted()
@@ -429,26 +447,21 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
429
447
 
430
448
  useLayoutEffect(() => {
431
449
  const isCustom = pageConfig.navigationStyle === 'custom'
432
- let opt = {}
450
+ const opt = {}
433
451
  if (__mpx_mode__ === 'android') {
434
- opt = {
435
- statusBarTranslucent: isCustom,
436
- statusBarStyle: pageConfig.statusBarStyle, // 枚举值 'auto' | 'dark' | 'light' 控制statusbar字体颜色
437
- statusBarColor: isCustom ? 'transparent' : pageConfig.statusBarColor // 控制statusbar背景颜色
438
- }
439
- } else if (__mpx_mode__ === 'ios') {
440
- opt = {
441
- headerBackTitleVisible: false
442
- }
452
+ // opt = {
453
+ // statusBarTranslucent: isCustom,
454
+ // statusBarStyle: pageConfig.statusBarStyle, // 枚举值 'auto' | 'dark' | 'light' 控制statusbar字体颜色
455
+ // statusBarColor: isCustom ? 'transparent' : pageConfig.statusBarColor // 控制statusbar背景颜色
456
+ // }
443
457
  }
444
458
  navigation.setOptions({
445
459
  headerShown: !isCustom,
446
- headerShadowVisible: false,
447
- headerTitle: pageConfig.navigationBarTitleText || '',
460
+ title: pageConfig.navigationBarTitleText || '',
448
461
  headerStyle: {
449
462
  backgroundColor: pageConfig.navigationBarBackgroundColor || '#000000'
450
463
  },
451
- headerTitleAlign: 'center',
464
+ // headerTitleAlign: 'center',
452
465
  headerTintColor: pageConfig.navigationBarTextStyle || 'white',
453
466
  ...opt
454
467
  })
@@ -484,9 +497,9 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
484
497
  value: currentPageId
485
498
  },
486
499
  createElement(IntersectionObserverContext.Provider,
487
- {
488
- value: intersectionObservers.current
489
- },
500
+ {
501
+ value: intersectionObservers.current
502
+ },
490
503
  createElement(defaultOptions,
491
504
  {
492
505
  navigation,
@@ -1,6 +1,6 @@
1
1
  import builtInKeysMap from '../builtInKeysMap'
2
2
  import mergeOptions from '../../../core/mergeOptions'
3
- import { diffAndCloneA, hasOwn } from '@mpxjs/utils'
3
+ import { diffAndCloneA, hasOwn, wrapMethodsWithErrorHandling } from '@mpxjs/utils'
4
4
  import { getCurrentInstance as getCurrentVueInstance } from '../../export/index'
5
5
  import MpxProxy, { setCurrentInstance, unsetCurrentInstance } from '../../../core/proxy'
6
6
  import {
@@ -27,6 +27,8 @@ function filterOptions (options) {
27
27
  )
28
28
  }
29
29
  }
30
+ } else if (key === 'methods') {
31
+ newOptions[key] = wrapMethodsWithErrorHandling(options[key])
30
32
  } else {
31
33
  newOptions[key] = options[key]
32
34
  }
@@ -62,7 +64,7 @@ export function getDefaultOptions ({ type, rawOptions = {} }) {
62
64
  }
63
65
  const setupRes = rawSetup(props, newContext)
64
66
  unsetCurrentInstance(instance.__mpxProxy)
65
- return setupRes
67
+ return wrapMethodsWithErrorHandling(setupRes, instance.__mpxProxy)
66
68
  }
67
69
  }
68
70
  const rootMixins = [{
@@ -1,4 +1,4 @@
1
- import { hasOwn, noop, isFunction } from '@mpxjs/utils'
1
+ import { hasOwn, noop, isFunction, wrapMethodsWithErrorHandling } from '@mpxjs/utils'
2
2
  import MpxProxy from '../../../core/proxy'
3
3
  import builtInKeysMap from '../builtInKeysMap'
4
4
  import mergeOptions from '../../../core/mergeOptions'
@@ -140,9 +140,14 @@ export function filterOptions (options) {
140
140
  if (!hasOwn(newOptions, 'properties')) {
141
141
  newOptions.properties = transformProperties(Object.assign({}, options.props, options.properties))
142
142
  }
143
- } else if (key === 'methods' && options.__pageCtor__) {
144
- // 构造器为Page时抽取所有methods方法到顶层
145
- Object.assign(newOptions, options[key])
143
+ } else if (key === 'methods') {
144
+ const newMethods = wrapMethodsWithErrorHandling(options[key])
145
+ if (options.__pageCtor__) {
146
+ // 构造器为Page时抽取所有methods方法到顶层
147
+ Object.assign(newOptions, newMethods)
148
+ } else {
149
+ newOptions[key] = newMethods
150
+ }
146
151
  } else {
147
152
  newOptions[key] = options[key]
148
153
  }
@@ -6,6 +6,9 @@ const factoryMap = {
6
6
 
7
7
  module.exports = (type) => (...args) => {
8
8
  if (type === 'Behavior') {
9
+ if (__mpx_mode__ === 'ali') {
10
+ return Mixin.apply(null, args)
11
+ }
9
12
  if (args[0]) {
10
13
  Object.defineProperty(args[0], '__mpx_behaviors_to_mixins__', {
11
14
  configurable: true,
@@ -1,2 +0,0 @@
1
- import directiveHelperMixin from './directiveHelperMixin.ios'
2
- export default directiveHelperMixin
@@ -1,2 +0,0 @@
1
- import proxyEventMixin from './proxyEventMixin.ios'
2
- export default proxyEventMixin
@@ -1,2 +0,0 @@
1
- import refsMixin from './refsMixin.ios'
2
- export default refsMixin
@@ -1,2 +0,0 @@
1
- import styleHelperMixin from './styleHelperMixin.ios'
2
- export default styleHelperMixin
@@ -1,2 +0,0 @@
1
- import createApp from './createApp.ios'
2
- export default createApp
@@ -1 +0,0 @@
1
- export { getDefaultOptions } from './getDefaultOptions.ios'