@mpxjs/core 2.9.69 → 2.9.70

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.
Files changed (38) hide show
  1. package/package.json +7 -3
  2. package/src/convertor/convertor.js +11 -32
  3. package/src/convertor/wxToAli.js +3 -3
  4. package/src/convertor/wxToSwan.js +3 -3
  5. package/src/convertor/wxToWeb.js +3 -3
  6. package/src/core/proxy.js +18 -12
  7. package/src/dynamic/dynamicRenderMixin.js +2 -2
  8. package/src/index.js +3 -14
  9. package/src/observer/reactive.js +5 -4
  10. package/src/observer/ref.js +3 -2
  11. package/src/observer/scheduler.js +4 -0
  12. package/src/observer/watch.js +5 -4
  13. package/src/platform/builtInMixins/directiveHelperMixin.ios.js +4 -1
  14. package/src/platform/builtInMixins/styleHelperMixin.ios.js +7 -4
  15. package/src/platform/createApp.ios.js +45 -33
  16. package/src/platform/createApp.js +7 -9
  17. package/src/platform/env/event.js +108 -0
  18. package/src/platform/env/index.ios.js +51 -0
  19. package/src/platform/env/index.js +8 -0
  20. package/src/platform/env/index.web.js +48 -0
  21. package/src/{external → platform/env}/vuePlugin.js +1 -1
  22. package/src/platform/export/index.js +1 -1
  23. package/src/platform/patch/{ali/getDefaultOptions.js → getDefaultOptions.ali.js} +3 -3
  24. package/src/platform/patch/{react/getDefaultOptions.ios.js → getDefaultOptions.ios.js} +263 -192
  25. package/src/platform/patch/{wx/getDefaultOptions.js → getDefaultOptions.js} +11 -5
  26. package/src/platform/patch/{web/getDefaultOptions.js → getDefaultOptions.web.js} +5 -5
  27. package/src/platform/patch/index.js +4 -21
  28. package/src/platform/patch/{ali/lifecycle.js → lifecycle/index.ali.js} +2 -0
  29. package/src/platform/patch/lifecycle/index.js +1 -0
  30. package/src/platform/patch/{swan/lifecycle.js → lifecycle/index.swan.js} +2 -0
  31. package/src/platform/patch/{web/lifecycle.js → lifecycle/index.web.js} +4 -0
  32. package/src/platform/patch/{wx/lifecycle.js → lifecycle/index.wx.js} +2 -0
  33. package/src/external/vue.js +0 -1
  34. package/src/external/vue.web.js +0 -6
  35. package/src/platform/patch/react/getDefaultOptions.js +0 -1
  36. package/src/platform/patch/swan/getDefaultOptions.js +0 -34
  37. /package/src/platform/export/{apiInject.js → inject.js} +0 -0
  38. /package/src/platform/export/{apiInject.web.js → inject.web.js} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mpxjs/core",
3
- "version": "2.9.69",
3
+ "version": "2.9.70",
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.69",
22
+ "@mpxjs/utils": "^2.9.70",
23
23
  "lodash": "^4.1.1",
24
24
  "miniprogram-api-typings": "^3.10.0"
25
25
  },
@@ -30,6 +30,7 @@
30
30
  "@mpxjs/store": "^2.9.0",
31
31
  "@react-navigation/native": "^7.0.3",
32
32
  "@react-navigation/stack": "^7.0.4",
33
+ "promise": "^8.3.0",
33
34
  "react": "*",
34
35
  "react-native": "*",
35
36
  "react-native-gesture-handler": "^2.19.0",
@@ -61,6 +62,9 @@
61
62
  "react-native": {
62
63
  "optional": true
63
64
  },
65
+ "promise": {
66
+ "optional": true
67
+ },
64
68
  "@react-navigation/native": {
65
69
  "optional": true
66
70
  },
@@ -105,5 +109,5 @@
105
109
  "url": "https://github.com/didi/mpx/issues"
106
110
  },
107
111
  "sideEffects": false,
108
- "gitHead": "e23c51acc4c2ffdd31fcc6c27aae1aed42d1ade2"
112
+ "gitHead": "ad8f04de95865ffc2b50b8c0a7f87b5952fb8647"
109
113
  }
@@ -1,9 +1,6 @@
1
- import * as wxLifecycle from '../platform/patch/wx/lifecycle'
2
- import * as aliLifecycle from '../platform/patch/ali/lifecycle'
3
- import * as webLifecycle from '../platform/patch/web/lifecycle'
4
- import * as swanLifecycle from '../platform/patch/swan/lifecycle'
1
+ import { LIFECYCLE, lifecycleProxyMap, pageMode } from '../platform/patch/lifecycle/index'
5
2
  import { mergeLifecycle } from './mergeLifecycle'
6
- import { error } from '@mpxjs/utils'
3
+ import { error, extend } from '@mpxjs/utils'
7
4
  import wxToAliRule from './wxToAli'
8
5
  import wxToWebRule from './wxToWeb'
9
6
  import wxToSwanRule from './wxToSwan'
@@ -13,24 +10,6 @@ import wxToDdRule from './wxToDd'
13
10
  import wxToJdRule from './wxToJd'
14
11
  import wxToReactRule from './wxToReact'
15
12
 
16
- // 根据当前环境获取的默认生命周期信息
17
- let lifecycleInfo
18
- let pageMode
19
-
20
- if (__mpx_mode__ === 'web') {
21
- lifecycleInfo = webLifecycle
22
- pageMode = ''
23
- } else if (__mpx_mode__ === 'ali') {
24
- lifecycleInfo = aliLifecycle
25
- pageMode = ''
26
- } else if (__mpx_mode__ === 'swan') {
27
- lifecycleInfo = swanLifecycle
28
- pageMode = 'blend'
29
- } else {
30
- lifecycleInfo = wxLifecycle
31
- pageMode = 'blend'
32
- }
33
-
34
13
  /**
35
14
  * 转换规则包含四点
36
15
  * lifecycle [object] 生命周期
@@ -40,25 +19,25 @@ if (__mpx_mode__ === 'web') {
40
19
  * convert [function] 自定义转换函数, 接收一个options
41
20
  */
42
21
  const defaultConvertRule = {
43
- lifecycle: mergeLifecycle(lifecycleInfo.LIFECYCLE),
44
- lifecycleProxyMap: lifecycleInfo.lifecycleProxyMap,
22
+ lifecycle: mergeLifecycle(LIFECYCLE),
23
+ lifecycleProxyMap: lifecycleProxyMap,
45
24
  pageMode,
46
25
  support: !!pageMode,
47
26
  convert: null
48
27
  }
49
28
 
50
29
  const rulesMap = {
51
- local: { ...defaultConvertRule },
30
+ local: extend({}, defaultConvertRule),
52
31
  default: defaultConvertRule,
53
32
  wxToWeb: wxToWebRule,
54
33
  wxToAli: wxToAliRule,
55
34
  wxToSwan: wxToSwanRule,
56
- wxToQq: { ...defaultConvertRule, ...wxToQqRule },
57
- wxToTt: { ...defaultConvertRule, ...wxToTtRule },
58
- wxToDd: { ...defaultConvertRule, ...wxToDdRule },
59
- wxToJd: { ...defaultConvertRule, ...wxToJdRule },
60
- wxToIos: { ...defaultConvertRule, ...wxToReactRule },
61
- wxToAndroid: { ...defaultConvertRule, ...wxToReactRule }
35
+ wxToQq: extend({}, defaultConvertRule, wxToQqRule),
36
+ wxToTt: extend({}, defaultConvertRule, wxToTtRule),
37
+ wxToDd: extend({}, defaultConvertRule, wxToDdRule),
38
+ wxToJd: extend({}, defaultConvertRule, wxToJdRule),
39
+ wxToIos: extend({}, defaultConvertRule, wxToReactRule),
40
+ wxToAndroid: extend({}, defaultConvertRule, wxToReactRule)
62
41
  }
63
42
 
64
43
  export function getConvertRule (convertMode) {
@@ -1,5 +1,5 @@
1
- import * as wxLifecycle from '../platform/patch/wx/lifecycle'
2
- import * as aliLifecycle from '../platform/patch/ali/lifecycle'
1
+ import * as wxLifecycle from '../platform/patch/lifecycle/index.wx'
2
+ import { LIFECYCLE } from '../platform/patch/lifecycle/index'
3
3
  import { mergeLifecycle } from './mergeLifecycle'
4
4
  import { error, hasOwn, isDev } from '@mpxjs/utils'
5
5
  import { implemented } from '../core/implement'
@@ -38,7 +38,7 @@ function notSupportTip (options) {
38
38
 
39
39
  export default {
40
40
  lifecycle: mergeLifecycle(wxLifecycle.LIFECYCLE),
41
- lifecycle2: mergeLifecycle(aliLifecycle.LIFECYCLE),
41
+ lifecycle2: mergeLifecycle(LIFECYCLE),
42
42
  pageMode: 'blend',
43
43
  support: false,
44
44
  lifecycleProxyMap: wxLifecycle.lifecycleProxyMap,
@@ -1,8 +1,8 @@
1
1
  import { error, isDev } from '@mpxjs/utils'
2
2
  import { implemented } from '../core/implement'
3
3
  import { mergeLifecycle } from './mergeLifecycle'
4
- import * as wxLifecycle from '../platform/patch/wx/lifecycle'
5
- import * as swanLifecycle from '../platform/patch/swan/lifecycle'
4
+ import * as wxLifecycle from '../platform/patch/lifecycle/index.wx'
5
+ import { LIFECYCLE } from '../platform/patch/lifecycle/index'
6
6
 
7
7
  const BEHAVIORS_MAP = {
8
8
  'wx://form-field': 'swan://form-field',
@@ -30,7 +30,7 @@ function notSupportTip (options) {
30
30
 
31
31
  export default {
32
32
  lifecycle: mergeLifecycle(wxLifecycle.LIFECYCLE),
33
- lifecycle2: mergeLifecycle(swanLifecycle.LIFECYCLE),
33
+ lifecycle2: mergeLifecycle(LIFECYCLE),
34
34
  pageMode: 'blend',
35
35
  support: true,
36
36
  lifecycleProxyMap: wxLifecycle.lifecycleProxyMap,
@@ -1,5 +1,5 @@
1
- import * as wxLifecycle from '../platform/patch/wx/lifecycle'
2
- import * as webLifecycle from '../platform/patch/web/lifecycle'
1
+ import * as wxLifecycle from '../platform/patch/lifecycle/index.wx'
2
+ import { LIFECYCLE } from '../platform/patch/lifecycle/index'
3
3
  import { mergeLifecycle } from './mergeLifecycle'
4
4
  import {
5
5
  isObject,
@@ -32,7 +32,7 @@ function notSupportTip (options) {
32
32
 
33
33
  export default {
34
34
  lifecycle: mergeLifecycle(wxLifecycle.LIFECYCLE),
35
- lifecycle2: mergeLifecycle(webLifecycle.LIFECYCLE),
35
+ lifecycle2: mergeLifecycle(LIFECYCLE),
36
36
  pageMode: 'blend',
37
37
  support: true,
38
38
  lifecycleProxyMap: wxLifecycle.lifecycleProxyMap,
package/src/core/proxy.js CHANGED
@@ -14,6 +14,7 @@ import {
14
14
  isEmptyObject,
15
15
  isPlainObject,
16
16
  isWeb,
17
+ isReact,
17
18
  doGetByPath,
18
19
  getByPath,
19
20
  setByPath,
@@ -50,7 +51,7 @@ import {
50
51
  } from './innerLifecycle'
51
52
  import contextMap from '../dynamic/vnode/context'
52
53
  import { getAst } from '../dynamic/astCache'
53
- import { inject, provide } from '../platform/export/apiInject'
54
+ import { inject, provide } from '../platform/export/inject'
54
55
 
55
56
  let uid = 0
56
57
 
@@ -116,7 +117,7 @@ export default class MpxProxy {
116
117
  this.ignoreProxyMap = makeMap(Mpx.config.ignoreProxyWhiteList)
117
118
  // 收集setup中动态注册的hooks,小程序与web环境都需要
118
119
  this.hooks = {}
119
- if (__mpx_mode__ !== 'web') {
120
+ if (!isWeb) {
120
121
  this.scope = effectScope(true)
121
122
  // props响应式数据代理
122
123
  this.props = {}
@@ -134,8 +135,12 @@ export default class MpxProxy {
134
135
  this.forceUpdateAll = false
135
136
  this.currentRenderTask = null
136
137
  this.propsUpdatedFlag = false
137
- // react专用,正确触发updated钩子
138
- this.pendingUpdatedFlag = false
138
+ if (isReact) {
139
+ // react专用,正确触发updated钩子
140
+ this.pendingUpdatedFlag = false
141
+ this.memoVersion = Symbol()
142
+ this.finalMemoVersion = Symbol()
143
+ }
139
144
  }
140
145
  this.initApi()
141
146
  }
@@ -160,7 +165,7 @@ export default class MpxProxy {
160
165
  // 缓存上下文,在 destoryed 阶段删除
161
166
  contextMap.set(this.uid, this.target)
162
167
  }
163
- if (__mpx_mode__ !== 'web') {
168
+ if (!isWeb) {
164
169
  // web中BEFORECREATE钩子通过vue的beforeCreate钩子单独驱动
165
170
  this.callHook(BEFORECREATE)
166
171
  setCurrentInstance(this)
@@ -179,7 +184,7 @@ export default class MpxProxy {
179
184
  this.state = CREATED
180
185
  this.callHook(CREATED)
181
186
 
182
- if (__mpx_mode__ !== 'web' && __mpx_mode__ !== 'ios' && __mpx_mode__ !== 'android') {
187
+ if (!isWeb && !isReact) {
183
188
  this.initRender()
184
189
  }
185
190
 
@@ -272,7 +277,7 @@ export default class MpxProxy {
272
277
  }
273
278
  // 挂载$rawOptions
274
279
  this.target.$rawOptions = this.options
275
- if (__mpx_mode__ !== 'web') {
280
+ if (!isWeb) {
276
281
  // 挂载$watch
277
282
  this.target.$watch = this.watch.bind(this)
278
283
  // 强制执行render
@@ -282,13 +287,14 @@ export default class MpxProxy {
282
287
  }
283
288
 
284
289
  initProps () {
285
- if (__mpx_mode__ === 'ios' || __mpx_mode__ === 'android') {
290
+ if (isReact) {
286
291
  // react模式下props内部对象透传无需深clone,依赖对象深层的数据响应触发子组件更新
287
292
  this.props = this.target.__getProps()
293
+ reactive(this.processIgnoreReactive(this.props))
288
294
  } else {
289
295
  this.props = diffAndCloneA(this.target.__getProps(this.options)).clone
296
+ reactive(this.processIgnoreReactive(this.props))
290
297
  }
291
- reactive(this.processIgnoreReactive(this.props))
292
298
  proxy(this.target, this.props, undefined, false, this.createProxyConflictHandler('props'))
293
299
  }
294
300
 
@@ -562,7 +568,7 @@ export default class MpxProxy {
562
568
  }
563
569
  if (!processed) {
564
570
  // 如果当前数据和上次的miniRenderData完全无关,但存在于组件的视图数据中,则与组件视图数据进行diff
565
- if (this.target.data && hasOwn(this.target.data, firstKey)) {
571
+ if (hasOwn(this.target.data, firstKey)) {
566
572
  const localInitialData = getByPath(this.target.data, key)
567
573
  const { clone, diff, diffData } = diffAndCloneA(data, localInitialData)
568
574
  this.miniRenderData[key] = clone
@@ -755,12 +761,12 @@ export default class MpxProxy {
755
761
  }
756
762
  setByPath(this.target, key, data[key])
757
763
  })
758
- this.forceUpdateData = data
764
+ Object.assign(this.forceUpdateData, data)
759
765
  } else {
760
766
  this.forceUpdateAll = true
761
767
  }
762
768
 
763
- if (__mpx_mode__ === 'ios' || __mpx_mode__ === 'android') {
769
+ if (isReact) {
764
770
  // rn中不需要setdata
765
771
  this.forceUpdateData = {}
766
772
  this.forceUpdateAll = false
@@ -1,4 +1,4 @@
1
- import { hasOwn, isObject, error } from '@mpxjs/utils'
1
+ import { hasOwn, error } from '@mpxjs/utils'
2
2
  import genVnodeTree from './vnode/render'
3
3
  import contextMap from './vnode/context'
4
4
  import { CREATED } from '../core/innerLifecycle'
@@ -56,7 +56,7 @@ function dynamicRenderHelperMixin () {
56
56
  methods: {
57
57
  _g (astData, moduleId) {
58
58
  const location = this.__mpxProxy && this.__mpxProxy.options.mpxFileResource
59
- if (astData && isObject(astData) && hasOwn(astData, 'template')) {
59
+ if (hasOwn(astData, 'template')) {
60
60
  const vnodeTree = genVnodeTree(astData, [this], { moduleId, location })
61
61
  return vnodeTree
62
62
  } else {
package/src/index.js CHANGED
@@ -1,8 +1,7 @@
1
- import Vue from './external/vue'
1
+
2
2
  import { error, diffAndCloneA, hasOwn, makeMap } from '@mpxjs/utils'
3
3
  import { APIs, InstanceAPIs } from './platform/export/api'
4
-
5
- import { createI18n } from './platform/builtInMixins/i18nMixin'
4
+ import { init } from './platform/env/index'
6
5
 
7
6
  export * from './platform/export/index'
8
7
 
@@ -123,10 +122,6 @@ function factory () {
123
122
 
124
123
  Object.assign(Mpx, APIs)
125
124
  Object.assign(Mpx.prototype, InstanceAPIs)
126
- // 输出web时在mpx上挂载Vue对象
127
- if (__mpx_mode__ === 'web') {
128
- Mpx.__vue = Vue
129
- }
130
125
  return Mpx
131
126
  }
132
127
 
@@ -156,12 +151,6 @@ Mpx.config = {
156
151
  rnConfig: {}
157
152
  }
158
153
 
159
- global.__mpx = Mpx
160
-
161
- if (__mpx_mode__ !== 'web') {
162
- if (global.i18n) {
163
- Mpx.i18n = createI18n(global.i18n)
164
- }
165
- }
154
+ init(Mpx)
166
155
 
167
156
  export default Mpx
@@ -34,6 +34,7 @@ export class Observer {
34
34
 
35
35
  constructor (value, shallow) {
36
36
  this.value = value
37
+ this.shallow = shallow
37
38
  def(value, ObKey, this)
38
39
  if (Array.isArray(value)) {
39
40
  const augment = hasProto && arrayProtoAugment
@@ -120,7 +121,7 @@ export function defineReactive (obj, key, val, shallow) {
120
121
  const getter = property && property.get
121
122
  const setter = property && property.set
122
123
 
123
- let childOb = !shallow && observe(val)
124
+ let childOb = shallow ? getObserver(val) : observe(val)
124
125
  Object.defineProperty(obj, key, {
125
126
  enumerable: true,
126
127
  configurable: true,
@@ -149,7 +150,7 @@ export function defineReactive (obj, key, val, shallow) {
149
150
  } else {
150
151
  val = newVal
151
152
  }
152
- childOb = !shallow && observe(newVal)
153
+ childOb = shallow ? getObserver(newVal) : observe(newVal)
153
154
  dep.notify()
154
155
  }
155
156
  })
@@ -175,7 +176,7 @@ export function set (target, key, val) {
175
176
  target[key] = val
176
177
  return val
177
178
  }
178
- defineReactive(ob.value, key, val)
179
+ defineReactive(ob.value, key, val, ob.shallow)
179
180
  ob.dep.notify()
180
181
  return val
181
182
  }
@@ -225,7 +226,7 @@ export function shallowReactive (value) {
225
226
  }
226
227
 
227
228
  export function isReactive (value) {
228
- return value && hasOwn(value, ObKey) && value[ObKey] instanceof Observer
229
+ return hasOwn(value, ObKey) && value[ObKey] instanceof Observer
229
230
  }
230
231
 
231
232
  export function getObserver (value) {
@@ -3,12 +3,13 @@ import { RefKey } from '../helper/const'
3
3
  import {
4
4
  warn,
5
5
  isPlainObject,
6
- hasOwn
6
+ hasOwn,
7
+ extend
7
8
  } from '@mpxjs/utils'
8
9
 
9
10
  export class RefImpl {
10
11
  constructor (options) {
11
- Object.defineProperty(this, 'value', { enumerable: true, ...options })
12
+ Object.defineProperty(this, 'value', extend({ enumerable: true }, options))
12
13
  }
13
14
  }
14
15
 
@@ -83,6 +83,10 @@ export function queueJob (job) {
83
83
  }
84
84
  }
85
85
 
86
+ export function hasPendingJob (job) {
87
+ return queue.length && queue.includes(job, isFlushing && job.allowRecurse ? flushIndex + 1 : flushIndex)
88
+ }
89
+
86
90
  function queueFlush () {
87
91
  if (!isFlushing && !isFlushPending) {
88
92
  isFlushPending = true
@@ -12,7 +12,8 @@ import {
12
12
  isArray,
13
13
  remove,
14
14
  callWithErrorHandling,
15
- hasChanged
15
+ hasChanged,
16
+ extend
16
17
  } from '@mpxjs/utils'
17
18
 
18
19
  export function watchEffect (effect, options) {
@@ -20,11 +21,11 @@ export function watchEffect (effect, options) {
20
21
  }
21
22
 
22
23
  export function watchPostEffect (effect, options) {
23
- return watch(effect, null, { ...options, flush: 'post' })
24
+ return watch(effect, null, extend({}, options, { flush: 'post' }))
24
25
  }
25
26
 
26
27
  export function watchSyncEffect (effect, options) {
27
- return watch(effect, null, { ...options, flush: 'sync' })
28
+ return watch(effect, null, extend({}, options, { flush: 'sync' }))
28
29
  }
29
30
 
30
31
  const warnInvalidSource = (s) => {
@@ -34,7 +35,7 @@ const warnInvalidSource = (s) => {
34
35
  const shouldTrigger = (value, oldValue) => hasChanged(value, oldValue) || isObject(value)
35
36
 
36
37
  const processWatchOptionsCompat = (options) => {
37
- const newOptions = { ...options }
38
+ const newOptions = extend({}, options)
38
39
  if (options.sync) {
39
40
  newOptions.flush = 'sync'
40
41
  }
@@ -1,7 +1,10 @@
1
1
  export default function directiveHelperMixin () {
2
2
  return {
3
3
  methods: {
4
- __getWxKey (item, key) {
4
+ __getWxKey (item, key, index) {
5
+ if (key === 'index') {
6
+ return index
7
+ }
5
8
  return key === '*this' ? item : item[key]
6
9
  }
7
10
  }
@@ -1,4 +1,4 @@
1
- import { isObject, isArray, dash2hump, cached } from '@mpxjs/utils'
1
+ import { isObject, isArray, dash2hump, cached, isEmptyObject } from '@mpxjs/utils'
2
2
  import { Dimensions, StyleSheet } from 'react-native'
3
3
 
4
4
  let { width, height } = Dimensions.get('screen')
@@ -26,6 +26,8 @@ const unit = {
26
26
  vh
27
27
  }
28
28
 
29
+ const empty = {}
30
+
29
31
  function formatValue (value) {
30
32
  const matched = unitRegExp.exec(value)
31
33
  if (matched) {
@@ -179,9 +181,9 @@ export default function styleHelperMixin () {
179
181
  } else if (appClassMap[className]) {
180
182
  // todo 全局样式在每个页面和组件中生效,以支持全局原子类,后续支持样式模块复用后可考虑移除
181
183
  Object.assign(result, appClassMap[className])
182
- } else if (this.props[className] && isObject(this.props[className])) {
184
+ } else if (isObject(this.__props[className])) {
183
185
  // externalClasses必定以对象形式传递下来
184
- Object.assign(result, this.props[className])
186
+ Object.assign(result, this.__props[className])
185
187
  }
186
188
  })
187
189
  }
@@ -196,7 +198,8 @@ export default function styleHelperMixin () {
196
198
  display: 'none'
197
199
  })
198
200
  }
199
- return result
201
+
202
+ return isEmptyObject(result) ? empty : result
200
203
  }
201
204
  }
202
205
  }
@@ -1,14 +1,15 @@
1
1
  import transferOptions from '../core/transferOptions'
2
2
  import builtInKeysMap from './patch/builtInKeysMap'
3
- import { makeMap, spreadProp, parseUrlQuery, getFocusedNavigation } from '@mpxjs/utils'
3
+ import { makeMap, spreadProp, getFocusedNavigation, hasOwn, extend } from '@mpxjs/utils'
4
4
  import { mergeLifecycle } from '../convertor/mergeLifecycle'
5
- import * as wxLifecycle from '../platform/patch/wx/lifecycle'
5
+ import { LIFECYCLE } from '../platform/patch/lifecycle/index'
6
6
  import Mpx from '../index'
7
7
  import { createElement, memo, useRef, useEffect } from 'react'
8
8
  import * as ReactNative from 'react-native'
9
+ import { Image } from 'react-native'
9
10
  import { ref } from '../observer/ref'
10
11
 
11
- const appHooksMap = makeMap(mergeLifecycle(wxLifecycle.LIFECYCLE).app)
12
+ const appHooksMap = makeMap(mergeLifecycle(LIFECYCLE).app)
12
13
 
13
14
  function getOrientation (window = ReactNative.Dimensions.get('window')) {
14
15
  return window.width > window.height ? 'landscape' : 'portrait'
@@ -30,11 +31,7 @@ function filterOptions (options, appData) {
30
31
  }
31
32
 
32
33
  function createAppInstance (appData) {
33
- const instance = {
34
- ...Mpx.prototype,
35
- ...appData
36
- }
37
- return instance
34
+ return extend({}, Mpx.prototype, appData)
38
35
  }
39
36
 
40
37
  export default function createApp (option, config = {}) {
@@ -84,12 +81,6 @@ export default function createApp (option, config = {}) {
84
81
  }
85
82
  }
86
83
 
87
- global.__mpxAppCbs = global.__mpxAppCbs || {
88
- show: [],
89
- hide: [],
90
- error: []
91
- }
92
-
93
84
  global.__mpxAppLaunched = false
94
85
 
95
86
  global.__mpxAppFocusedState = ref('show')
@@ -105,14 +96,10 @@ export default function createApp (option, config = {}) {
105
96
  })
106
97
 
107
98
  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
- }
99
+ const { initialRouteName, initialParams } = Mpx.config.rnConfig.parseAppProps?.(props) || {}
100
+ initialRouteRef.current.initialRouteName = initialRouteName || initialRouteRef.current.initialRouteName
101
+ initialRouteRef.current.initialParams = initialParams || initialRouteRef.current.initialParams
102
+
116
103
  global.__mpxAppOnLaunch = (navigation) => {
117
104
  global.__mpxAppLaunched = true
118
105
  const state = navigation.getState()
@@ -140,6 +127,9 @@ export default function createApp (option, config = {}) {
140
127
  if (defaultOptions.onError) {
141
128
  global.__mpxAppCbs.error.push(defaultOptions.onError.bind(instance))
142
129
  }
130
+ if (defaultOptions.onUnhandledRejection) {
131
+ global.__mpxAppCbs.rejection.push(defaultOptions.onUnhandledRejection.bind(instance))
132
+ }
143
133
 
144
134
  const changeSubscription = ReactNative.AppState.addEventListener('change', (currentState) => {
145
135
  if (currentState === 'active') {
@@ -159,12 +149,17 @@ export default function createApp (option, config = {}) {
159
149
  global.__mpxAppCbs.show.forEach((cb) => {
160
150
  cb(options)
161
151
  })
162
- global.__mpxAppFocusedState.value = 'show'
163
- } else if (currentState === 'inactive') {
152
+ if (navigation && hasOwn(global.__mpxPageStatusMap, navigation.pageId)) {
153
+ global.__mpxPageStatusMap[navigation.pageId] = 'show'
154
+ }
155
+ } else if (currentState === 'inactive' || currentState === 'background') {
164
156
  global.__mpxAppCbs.hide.forEach((cb) => {
165
157
  cb()
166
158
  })
167
- global.__mpxAppFocusedState.value = 'hide'
159
+ const navigation = getFocusedNavigation()
160
+ if (navigation && hasOwn(global.__mpxPageStatusMap, navigation.pageId)) {
161
+ global.__mpxPageStatusMap[navigation.pageId] = 'hide'
162
+ }
168
163
  }
169
164
  })
170
165
 
@@ -174,7 +169,10 @@ export default function createApp (option, config = {}) {
174
169
  const orientation = getOrientation(window)
175
170
  if (orientation === lastOrientation) return
176
171
  lastOrientation = orientation
177
- global.__mpxAppFocusedState.value = `resize${count++}`
172
+ const navigation = getFocusedNavigation()
173
+ if (navigation && hasOwn(global.__mpxPageStatusMap, navigation.pageId)) {
174
+ global.__mpxPageStatusMap[navigation.pageId] = `resize${count++}`
175
+ }
178
176
  })
179
177
  return () => {
180
178
  changeSubscription && changeSubscription.remove()
@@ -183,6 +181,19 @@ export default function createApp (option, config = {}) {
183
181
  }, [])
184
182
 
185
183
  const { initialRouteName, initialParams } = initialRouteRef.current
184
+ const headerBackImageProps = Mpx.config.rnConfig.headerBackImageProps || null
185
+ const navScreenOpts = {
186
+ // 7.x替换headerBackTitleVisible
187
+ // headerBackButtonDisplayMode: 'minimal',
188
+ headerBackTitleVisible: false,
189
+ // 安卓上会出现初始化时闪现导航条的问题
190
+ headerShown: false
191
+ }
192
+ if (headerBackImageProps) {
193
+ navScreenOpts.headerBackImage = () => {
194
+ return createElement(Image, headerBackImageProps)
195
+ }
196
+ }
186
197
  return createElement(SafeAreaProvider,
187
198
  null,
188
199
  createElement(NavigationContainer,
@@ -193,13 +204,7 @@ export default function createApp (option, config = {}) {
193
204
  createElement(Stack.Navigator,
194
205
  {
195
206
  initialRouteName,
196
- screenOptions: {
197
- gestureEnabled: true,
198
- // 7.x替换headerBackTitleVisible
199
- // headerBackButtonDisplayMode: 'minimal',
200
- headerBackTitleVisible: false,
201
- headerMode: 'float'
202
- }
207
+ screenOptions: navScreenOpts
203
208
  },
204
209
  ...getPageScreens(initialRouteName, initialParams)
205
210
  )
@@ -216,4 +221,11 @@ export default function createApp (option, config = {}) {
216
221
  }
217
222
  return []
218
223
  }
224
+
225
+ global.setCurrentPageStatus = function (status) {
226
+ const navigation = getFocusedNavigation()
227
+ if (navigation && hasOwn(global.__mpxPageStatusMap, navigation.pageId)) {
228
+ global.__mpxPageStatusMap[navigation.pageId] = status
229
+ }
230
+ }
219
231
  }