@mpxjs/core 2.9.70 → 2.9.72
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/package.json +4 -8
- package/src/convertor/wxToReact.js +1 -1
- package/src/core/mergeOptions.js +3 -6
- package/src/core/proxy.js +25 -19
- package/src/platform/builtInMixins/index.js +2 -1
- package/src/platform/builtInMixins/proxyEventMixin.web.js +53 -5
- package/src/platform/builtInMixins/relationsMixin.ios.js +67 -0
- package/src/platform/createApp.ios.js +37 -36
- package/src/platform/createApp.js +24 -26
- package/src/platform/env/event.js +44 -47
- package/src/platform/env/index.ios.js +19 -9
- package/src/platform/env/index.web.js +1 -1
- package/src/platform/env/vuePlugin.js +9 -3
- package/src/platform/export/inject.js +16 -26
- package/src/platform/patch/getDefaultOptions.ios.js +92 -12
- package/src/platform/patch/getDefaultOptions.js +0 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mpxjs/core",
|
|
3
|
-
"version": "2.9.
|
|
3
|
+
"version": "2.9.72",
|
|
4
4
|
"description": "mpx runtime core",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"miniprogram",
|
|
@@ -24,17 +24,16 @@
|
|
|
24
24
|
"miniprogram-api-typings": "^3.10.0"
|
|
25
25
|
},
|
|
26
26
|
"peerDependencies": {
|
|
27
|
-
"@ant-design/react-native": "^5.1.3",
|
|
28
27
|
"@d11/react-native-fast-image": "^8.6.12",
|
|
29
28
|
"@mpxjs/api-proxy": "^2.9.0",
|
|
30
29
|
"@mpxjs/store": "^2.9.0",
|
|
31
30
|
"@react-navigation/native": "^7.0.3",
|
|
32
31
|
"@react-navigation/stack": "^7.0.4",
|
|
33
|
-
"promise": "^8.3.0",
|
|
34
32
|
"react": "*",
|
|
35
33
|
"react-native": "*",
|
|
36
34
|
"react-native-gesture-handler": "^2.19.0",
|
|
37
35
|
"react-native-linear-gradient": "^2.8.3",
|
|
36
|
+
"react-native-reanimated": "^3.15.2",
|
|
38
37
|
"react-native-safe-area-context": "^4.14.0",
|
|
39
38
|
"react-native-screens": "^4.1.0",
|
|
40
39
|
"react-native-webview": "^13.10.5",
|
|
@@ -62,7 +61,7 @@
|
|
|
62
61
|
"react-native": {
|
|
63
62
|
"optional": true
|
|
64
63
|
},
|
|
65
|
-
"
|
|
64
|
+
"react-native-reanimated": {
|
|
66
65
|
"optional": true
|
|
67
66
|
},
|
|
68
67
|
"@react-navigation/native": {
|
|
@@ -71,9 +70,6 @@
|
|
|
71
70
|
"@react-navigation/stack": {
|
|
72
71
|
"optional": true
|
|
73
72
|
},
|
|
74
|
-
"@ant-design/react-native": {
|
|
75
|
-
"optional": true
|
|
76
|
-
},
|
|
77
73
|
"react-native-safe-area-context": {
|
|
78
74
|
"optional": true
|
|
79
75
|
},
|
|
@@ -109,5 +105,5 @@
|
|
|
109
105
|
"url": "https://github.com/didi/mpx/issues"
|
|
110
106
|
},
|
|
111
107
|
"sideEffects": false,
|
|
112
|
-
"gitHead": "
|
|
108
|
+
"gitHead": "5ceca0430a79a41456260d87a81760f2cd31fad1"
|
|
113
109
|
}
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
import { implemented } from '../core/implement'
|
|
6
6
|
|
|
7
7
|
// 暂不支持的wx选项,后期需要各种花式支持
|
|
8
|
-
const unsupported = ['
|
|
8
|
+
const unsupported = ['moved', 'definitionFilter']
|
|
9
9
|
|
|
10
10
|
function convertErrorDesc (key) {
|
|
11
11
|
error(`Options.${key} is not supported in runtime conversion from wx to react native.`, global.currentResource)
|
package/src/core/mergeOptions.js
CHANGED
|
@@ -122,9 +122,10 @@ function extractObservers (options) {
|
|
|
122
122
|
Object.keys(props).forEach(key => {
|
|
123
123
|
const prop = props[key]
|
|
124
124
|
if (prop && prop.observer) {
|
|
125
|
+
let callback = prop.observer
|
|
126
|
+
delete prop.observer
|
|
125
127
|
mergeWatch(key, {
|
|
126
128
|
handler (...rest) {
|
|
127
|
-
let callback = prop.observer
|
|
128
129
|
if (typeof callback === 'string') {
|
|
129
130
|
callback = this[callback]
|
|
130
131
|
}
|
|
@@ -168,11 +169,7 @@ function extractObservers (options) {
|
|
|
168
169
|
cb = this[cb]
|
|
169
170
|
}
|
|
170
171
|
if (typeof cb === 'function') {
|
|
171
|
-
|
|
172
|
-
val = [val]
|
|
173
|
-
old = [old]
|
|
174
|
-
}
|
|
175
|
-
cb.call(this, ...val, ...old)
|
|
172
|
+
Array.isArray(val) ? cb.call(this, ...val) : cb.call(this, val)
|
|
176
173
|
}
|
|
177
174
|
},
|
|
178
175
|
deep,
|
package/src/core/proxy.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { reactive } from '../observer/reactive'
|
|
1
|
+
import { reactive, defineReactive } from '../observer/reactive'
|
|
2
2
|
import { ReactiveEffect, pauseTracking, resetTracking } from '../observer/effect'
|
|
3
3
|
import { effectScope } from '../platform/export/index'
|
|
4
4
|
import { watch } from '../observer/watch'
|
|
@@ -111,7 +111,7 @@ export default class MpxProxy {
|
|
|
111
111
|
this.uid = uid++
|
|
112
112
|
this.name = options.name || ''
|
|
113
113
|
this.options = options
|
|
114
|
-
this.
|
|
114
|
+
this.shallowReactivePattern = this.options.options?.shallowReactivePattern
|
|
115
115
|
// beforeCreate -> created -> mounted -> unmounted
|
|
116
116
|
this.state = BEFORECREATE
|
|
117
117
|
this.ignoreProxyMap = makeMap(Mpx.config.ignoreProxyWhiteList)
|
|
@@ -145,10 +145,12 @@ export default class MpxProxy {
|
|
|
145
145
|
this.initApi()
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
-
|
|
149
|
-
if (this.
|
|
148
|
+
processShallowReactive (obj) {
|
|
149
|
+
if (this.shallowReactivePattern && isObject(obj)) {
|
|
150
150
|
Object.keys(obj).forEach((key) => {
|
|
151
|
-
if (this.
|
|
151
|
+
if (this.shallowReactivePattern.test(key)) {
|
|
152
|
+
// 命中shallowReactivePattern的属性将其设置为 shallowReactive
|
|
153
|
+
defineReactive(obj, key, obj[key], true)
|
|
152
154
|
Object.defineProperty(obj, key, {
|
|
153
155
|
enumerable: true,
|
|
154
156
|
// set configurable to false to skip defineReactive
|
|
@@ -169,6 +171,8 @@ export default class MpxProxy {
|
|
|
169
171
|
// web中BEFORECREATE钩子通过vue的beforeCreate钩子单独驱动
|
|
170
172
|
this.callHook(BEFORECREATE)
|
|
171
173
|
setCurrentInstance(this)
|
|
174
|
+
this.parent = this.resolveParent()
|
|
175
|
+
this.provides = this.parent ? this.parent.provides : Object.create(null)
|
|
172
176
|
// 在 props/data 初始化之前初始化 inject
|
|
173
177
|
this.initInject()
|
|
174
178
|
this.initProps()
|
|
@@ -193,6 +197,18 @@ export default class MpxProxy {
|
|
|
193
197
|
}
|
|
194
198
|
}
|
|
195
199
|
|
|
200
|
+
resolveParent () {
|
|
201
|
+
if (isReact) {
|
|
202
|
+
return {
|
|
203
|
+
provides: this.target.__parentProvides
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
if (isFunction(this.target.selectOwnerComponent)) {
|
|
207
|
+
const parent = this.target.selectOwnerComponent()
|
|
208
|
+
return parent ? parent.__mpxProxy : null
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
196
212
|
createRenderTask (isEmptyRender) {
|
|
197
213
|
if ((!this.isMounted() && this.currentRenderTask) || (this.isMounted() && isEmptyRender)) {
|
|
198
214
|
return
|
|
@@ -232,16 +248,6 @@ export default class MpxProxy {
|
|
|
232
248
|
// 页面/组件销毁清除上下文的缓存
|
|
233
249
|
contextMap.remove(this.uid)
|
|
234
250
|
}
|
|
235
|
-
if (!isWeb && this.options.__type__ === 'page') {
|
|
236
|
-
// 小程序页面销毁时移除对应的 provide
|
|
237
|
-
if (isFunction(this.target.getPageId)) {
|
|
238
|
-
const pageId = this.target.getPageId()
|
|
239
|
-
const providesMap = global.__mpxProvidesMap
|
|
240
|
-
if (providesMap.__pages[pageId]) {
|
|
241
|
-
delete providesMap.__pages[pageId]
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
251
|
this.callHook(BEFOREUNMOUNT)
|
|
246
252
|
this.scope?.stop()
|
|
247
253
|
if (this.update) this.update.active = false
|
|
@@ -290,10 +296,10 @@ export default class MpxProxy {
|
|
|
290
296
|
if (isReact) {
|
|
291
297
|
// react模式下props内部对象透传无需深clone,依赖对象深层的数据响应触发子组件更新
|
|
292
298
|
this.props = this.target.__getProps()
|
|
293
|
-
reactive(this.
|
|
299
|
+
reactive(this.processShallowReactive(this.props))
|
|
294
300
|
} else {
|
|
295
301
|
this.props = diffAndCloneA(this.target.__getProps(this.options)).clone
|
|
296
|
-
reactive(this.
|
|
302
|
+
reactive(this.processShallowReactive(this.props))
|
|
297
303
|
}
|
|
298
304
|
proxy(this.target, this.props, undefined, false, this.createProxyConflictHandler('props'))
|
|
299
305
|
}
|
|
@@ -333,7 +339,7 @@ export default class MpxProxy {
|
|
|
333
339
|
if (isFunction(dataFn)) {
|
|
334
340
|
Object.assign(this.data, callWithErrorHandling(dataFn.bind(this.target), this, 'data function'))
|
|
335
341
|
}
|
|
336
|
-
reactive(this.
|
|
342
|
+
reactive(this.processShallowReactive(this.data))
|
|
337
343
|
proxy(this.target, this.data, undefined, false, this.createProxyConflictHandler('data'))
|
|
338
344
|
this.collectLocalKeys(this.data)
|
|
339
345
|
}
|
|
@@ -514,7 +520,7 @@ export default class MpxProxy {
|
|
|
514
520
|
if (hasOwn(renderData, key)) {
|
|
515
521
|
const data = renderData[key]
|
|
516
522
|
const firstKey = getFirstKey(key)
|
|
517
|
-
if (!this.localKeysMap[firstKey]
|
|
523
|
+
if (!this.localKeysMap[firstKey]) {
|
|
518
524
|
continue
|
|
519
525
|
}
|
|
520
526
|
// 外部clone,用于只需要clone的场景
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { setByPath } from '@mpxjs/utils'
|
|
1
|
+
import { setByPath, error, parseDataset } from '@mpxjs/utils'
|
|
2
|
+
import Mpx from '../../index'
|
|
2
3
|
|
|
3
4
|
export default function proxyEventMixin () {
|
|
4
5
|
return {
|
|
@@ -19,11 +20,58 @@ export default function proxyEventMixin () {
|
|
|
19
20
|
const value = filterMethod ? (innerFilter[filterMethod] ? innerFilter[filterMethod](originValue) : typeof this[filterMethod] === 'function' && this[filterMethod]) : originValue
|
|
20
21
|
setByPath(this, expr, value)
|
|
21
22
|
},
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
__invoke (rawEvent, eventConfig = []) {
|
|
24
|
+
if (typeof Mpx.config.proxyEventHandler === 'function') {
|
|
25
|
+
try {
|
|
26
|
+
Mpx.config.proxyEventHandler(rawEvent)
|
|
27
|
+
} catch (e) {}
|
|
26
28
|
}
|
|
29
|
+
const location = this.__mpxProxy.options.mpxFileResource
|
|
30
|
+
|
|
31
|
+
if (rawEvent.target && !rawEvent.target._datasetProcessed) {
|
|
32
|
+
const originalDataset = rawEvent.target.dataset
|
|
33
|
+
Object.defineProperty(rawEvent.target, 'dataset', {
|
|
34
|
+
get: () => parseDataset(originalDataset),
|
|
35
|
+
configurable: true,
|
|
36
|
+
enumerable: true
|
|
37
|
+
})
|
|
38
|
+
rawEvent.target._datasetProcessed = true
|
|
39
|
+
}
|
|
40
|
+
if (rawEvent.currentTarget && !rawEvent.currentTarget._datasetProcessed) {
|
|
41
|
+
const originalDataset = rawEvent.currentTarget.dataset
|
|
42
|
+
Object.defineProperty(rawEvent.currentTarget, 'dataset', {
|
|
43
|
+
get: () => parseDataset(originalDataset),
|
|
44
|
+
configurable: true,
|
|
45
|
+
enumerable: true
|
|
46
|
+
})
|
|
47
|
+
rawEvent.currentTarget._datasetProcessed = true
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
let returnedValue
|
|
51
|
+
eventConfig.forEach((item) => {
|
|
52
|
+
const callbackName = item[0]
|
|
53
|
+
if (callbackName) {
|
|
54
|
+
const params =
|
|
55
|
+
item.length > 1
|
|
56
|
+
? item.slice(1).map((item) => {
|
|
57
|
+
if (item === '__mpx_event__') {
|
|
58
|
+
return rawEvent
|
|
59
|
+
} else {
|
|
60
|
+
return item
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
: [rawEvent]
|
|
64
|
+
if (typeof this[callbackName] === 'function') {
|
|
65
|
+
returnedValue = this[callbackName].apply(this, params)
|
|
66
|
+
} else {
|
|
67
|
+
error(
|
|
68
|
+
`Instance property [${callbackName}] is not function, please check.`,
|
|
69
|
+
location
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
})
|
|
74
|
+
return returnedValue
|
|
27
75
|
}
|
|
28
76
|
}
|
|
29
77
|
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { BEFORECREATE, MOUNTED, BEFOREUNMOUNT } from '../../core/innerLifecycle'
|
|
2
|
+
|
|
3
|
+
const relationTypeMap = {
|
|
4
|
+
parent: 'child',
|
|
5
|
+
ancestor: 'descendant'
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export default function relationsMixin (mixinType) {
|
|
9
|
+
if (mixinType === 'component') {
|
|
10
|
+
return {
|
|
11
|
+
[BEFORECREATE] () {
|
|
12
|
+
this.__relationNodesMap = {}
|
|
13
|
+
},
|
|
14
|
+
[MOUNTED] () {
|
|
15
|
+
this.__mpxExecRelations('linked')
|
|
16
|
+
},
|
|
17
|
+
[BEFOREUNMOUNT] () {
|
|
18
|
+
this.__mpxExecRelations('unlinked')
|
|
19
|
+
this.__relationNodesMap = {}
|
|
20
|
+
},
|
|
21
|
+
methods: {
|
|
22
|
+
getRelationNodes (path) {
|
|
23
|
+
return this.__relationNodesMap[path] || null
|
|
24
|
+
},
|
|
25
|
+
__mpxExecRelations (type) {
|
|
26
|
+
const relations = this.__mpxProxy.options.relations
|
|
27
|
+
const relationContext = this.__relation
|
|
28
|
+
const currentPath = this.__componentPath
|
|
29
|
+
if (relations && relationContext) {
|
|
30
|
+
Object.keys(relations).forEach((path) => {
|
|
31
|
+
const relation = relations[path]
|
|
32
|
+
const relationType = relation.type
|
|
33
|
+
if ((relationType === 'parent' || relationType === 'ancestor') && relationContext[path]) {
|
|
34
|
+
const target = relationContext[path]
|
|
35
|
+
const targetRelation = target.__mpxProxy.options.relations?.[currentPath]
|
|
36
|
+
if (targetRelation && targetRelation.type === relationTypeMap[relationType] && target.__componentPath === path) {
|
|
37
|
+
if (type === 'linked') {
|
|
38
|
+
this.__mpxLinkRelationNodes(target, currentPath)
|
|
39
|
+
} else if (type === 'unlinked') {
|
|
40
|
+
this.__mpxRemoveRelationNodes(target, currentPath)
|
|
41
|
+
}
|
|
42
|
+
if (typeof targetRelation[type] === 'function') {
|
|
43
|
+
targetRelation[type].call(target, this)
|
|
44
|
+
}
|
|
45
|
+
if (typeof relation[type] === 'function') {
|
|
46
|
+
relation[type].call(this, target)
|
|
47
|
+
}
|
|
48
|
+
this.__relationNodesMap[path] = [target]
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
__mpxLinkRelationNodes (target, path) {
|
|
55
|
+
target.__relationNodesMap[path] = target.__relationNodesMap[path] || [] // 父级绑定子级
|
|
56
|
+
target.__relationNodesMap[path].push(this)
|
|
57
|
+
},
|
|
58
|
+
__mpxRemoveRelationNodes (target, path) {
|
|
59
|
+
const relationNodesMap = target.__relationNodesMap
|
|
60
|
+
const arr = relationNodesMap[path] || []
|
|
61
|
+
const index = arr.indexOf(this)
|
|
62
|
+
if (index !== -1) arr.splice(index, 1)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import transferOptions from '../core/transferOptions'
|
|
2
2
|
import builtInKeysMap from './patch/builtInKeysMap'
|
|
3
|
-
import { makeMap, spreadProp, getFocusedNavigation, hasOwn
|
|
3
|
+
import { makeMap, spreadProp, getFocusedNavigation, hasOwn } from '@mpxjs/utils'
|
|
4
4
|
import { mergeLifecycle } from '../convertor/mergeLifecycle'
|
|
5
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
9
|
import { Image } from 'react-native'
|
|
10
|
-
import {
|
|
10
|
+
import { initAppProvides } from './export/inject'
|
|
11
11
|
|
|
12
12
|
const appHooksMap = makeMap(mergeLifecycle(LIFECYCLE).app)
|
|
13
13
|
|
|
@@ -30,22 +30,28 @@ function filterOptions (options, appData) {
|
|
|
30
30
|
return newOptions
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
function
|
|
34
|
-
return extend({}, Mpx.prototype, appData)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export default function createApp (option, config = {}) {
|
|
33
|
+
export default function createApp (options) {
|
|
38
34
|
const appData = {}
|
|
39
35
|
|
|
40
36
|
const { NavigationContainer, createStackNavigator, SafeAreaProvider } = global.__navigationHelper
|
|
41
37
|
// app选项目前不需要进行转换
|
|
42
|
-
const { rawOptions, currentInject } = transferOptions(
|
|
38
|
+
const { rawOptions, currentInject } = transferOptions(options, 'app', false)
|
|
39
|
+
initAppProvides(rawOptions.provide, rawOptions)
|
|
43
40
|
const defaultOptions = filterOptions(spreadProp(rawOptions, 'methods'), appData)
|
|
44
|
-
defaultOptions.onAppInit && defaultOptions.onAppInit()
|
|
45
41
|
// 在页面script执行前填充getApp()
|
|
46
42
|
global.getApp = function () {
|
|
47
43
|
return appData
|
|
48
44
|
}
|
|
45
|
+
|
|
46
|
+
// 模拟小程序appInstance在热启动时不会重新创建的行为,在外部创建跟随js context的appInstance
|
|
47
|
+
const appInstance = Object.assign({}, appData, Mpx.prototype)
|
|
48
|
+
|
|
49
|
+
defaultOptions.onShow && global.__mpxAppCbs.show.push(defaultOptions.onShow.bind(appInstance))
|
|
50
|
+
defaultOptions.onHide && global.__mpxAppCbs.hide.push(defaultOptions.onHide.bind(appInstance))
|
|
51
|
+
defaultOptions.onError && global.__mpxAppCbs.error.push(defaultOptions.onError.bind(appInstance))
|
|
52
|
+
defaultOptions.onUnhandledRejection && global.__mpxAppCbs.rejection.push(defaultOptions.onUnhandledRejection.bind(appInstance))
|
|
53
|
+
defaultOptions.onAppInit && defaultOptions.onAppInit()
|
|
54
|
+
|
|
49
55
|
const pages = currentInject.getPages() || {}
|
|
50
56
|
const firstPage = currentInject.firstPage
|
|
51
57
|
const Stack = createStackNavigator()
|
|
@@ -82,55 +88,50 @@ export default function createApp (option, config = {}) {
|
|
|
82
88
|
}
|
|
83
89
|
|
|
84
90
|
global.__mpxAppLaunched = false
|
|
85
|
-
|
|
86
|
-
global.__mpxAppFocusedState = ref('show')
|
|
87
91
|
global.__mpxOptionsMap[currentInject.moduleId] = memo((props) => {
|
|
88
|
-
const
|
|
89
|
-
if (!instanceRef.current) {
|
|
90
|
-
instanceRef.current = createAppInstance(appData)
|
|
91
|
-
}
|
|
92
|
-
const instance = instanceRef.current
|
|
92
|
+
const firstRef = useRef(true)
|
|
93
93
|
const initialRouteRef = useRef({
|
|
94
94
|
initialRouteName: firstPage,
|
|
95
95
|
initialParams: {}
|
|
96
96
|
})
|
|
97
|
-
|
|
98
|
-
|
|
97
|
+
if (firstRef.current) {
|
|
98
|
+
// 热启动情况下,app会被销毁重建,将__mpxAppHotLaunched重置保障路由等初始化逻辑正确执行
|
|
99
|
+
global.__mpxAppHotLaunched = false
|
|
100
|
+
// 热启动情况下重置__mpxPagesMap避免页面销毁函数未及时执行时错误地引用到之前的navigation
|
|
101
|
+
global.__mpxPagesMap = {}
|
|
102
|
+
firstRef.current = false
|
|
103
|
+
}
|
|
104
|
+
if (!global.__mpxAppHotLaunched) {
|
|
99
105
|
const { initialRouteName, initialParams } = Mpx.config.rnConfig.parseAppProps?.(props) || {}
|
|
100
106
|
initialRouteRef.current.initialRouteName = initialRouteName || initialRouteRef.current.initialRouteName
|
|
101
107
|
initialRouteRef.current.initialParams = initialParams || initialRouteRef.current.initialParams
|
|
102
108
|
|
|
103
109
|
global.__mpxAppOnLaunch = (navigation) => {
|
|
104
|
-
global.__mpxAppLaunched = true
|
|
105
110
|
const state = navigation.getState()
|
|
106
111
|
Mpx.config.rnConfig.onStateChange?.(state)
|
|
107
112
|
const current = state.routes[state.index]
|
|
108
|
-
|
|
113
|
+
const options = {
|
|
109
114
|
path: current.name,
|
|
110
115
|
query: current.params,
|
|
111
116
|
scene: 0,
|
|
112
117
|
shareTicket: '',
|
|
113
|
-
referrerInfo: {}
|
|
118
|
+
referrerInfo: {},
|
|
119
|
+
isLaunch: true
|
|
120
|
+
}
|
|
121
|
+
global.__mpxEnterOptions = options
|
|
122
|
+
if (!global.__mpxAppLaunched) {
|
|
123
|
+
global.__mpxLaunchOptions = options
|
|
124
|
+
defaultOptions.onLaunch && defaultOptions.onLaunch.call(appInstance, options)
|
|
114
125
|
}
|
|
115
|
-
|
|
116
|
-
|
|
126
|
+
global.__mpxAppCbs.show.forEach((cb) => {
|
|
127
|
+
cb(options)
|
|
128
|
+
})
|
|
129
|
+
global.__mpxAppLaunched = true
|
|
130
|
+
global.__mpxAppHotLaunched = true
|
|
117
131
|
}
|
|
118
132
|
}
|
|
119
133
|
|
|
120
134
|
useEffect(() => {
|
|
121
|
-
if (defaultOptions.onShow) {
|
|
122
|
-
global.__mpxAppCbs.show.push(defaultOptions.onShow.bind(instance))
|
|
123
|
-
}
|
|
124
|
-
if (defaultOptions.onHide) {
|
|
125
|
-
global.__mpxAppCbs.hide.push(defaultOptions.onHide.bind(instance))
|
|
126
|
-
}
|
|
127
|
-
if (defaultOptions.onError) {
|
|
128
|
-
global.__mpxAppCbs.error.push(defaultOptions.onError.bind(instance))
|
|
129
|
-
}
|
|
130
|
-
if (defaultOptions.onUnhandledRejection) {
|
|
131
|
-
global.__mpxAppCbs.rejection.push(defaultOptions.onUnhandledRejection.bind(instance))
|
|
132
|
-
}
|
|
133
|
-
|
|
134
135
|
const changeSubscription = ReactNative.AppState.addEventListener('change', (currentState) => {
|
|
135
136
|
if (currentState === 'active') {
|
|
136
137
|
let options = global.__mpxEnterOptions
|
|
@@ -24,19 +24,29 @@ function filterOptions (options, appData) {
|
|
|
24
24
|
return newOptions
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
export default function createApp (
|
|
28
|
-
|
|
27
|
+
export default function createApp (options, config = {}) {
|
|
28
|
+
const appData = {}
|
|
29
|
+
// app选项目前不需要进行转换
|
|
30
|
+
const { rawOptions, currentInject } = transferOptions(options, 'app', false)
|
|
29
31
|
const builtInMixins = [{
|
|
32
|
+
// 在App中挂载mpx对象供周边工具访问,如e2e测试
|
|
30
33
|
getMpx () {
|
|
31
34
|
return Mpx
|
|
32
35
|
}
|
|
33
36
|
}]
|
|
34
|
-
const appData = {}
|
|
35
37
|
if (__mpx_mode__ === 'web') {
|
|
36
38
|
builtInMixins.push({
|
|
39
|
+
beforeCreate () {
|
|
40
|
+
// for vue provide vm access
|
|
41
|
+
Object.assign(this, appData, Mpx.prototype)
|
|
42
|
+
if (isBrowser) {
|
|
43
|
+
rawOptions.onShow && global.__mpxAppCbs.show.push(rawOptions.onShow.bind(this))
|
|
44
|
+
rawOptions.onHide && global.__mpxAppCbs.hide.push(rawOptions.onHide.bind(this))
|
|
45
|
+
rawOptions.onError && global.__mpxAppCbs.error.push(rawOptions.onError.bind(this))
|
|
46
|
+
rawOptions.onUnhandledRejection && global.__mpxAppCbs.rejection.push(rawOptions.onUnhandledRejection.bind(this))
|
|
47
|
+
}
|
|
48
|
+
},
|
|
37
49
|
created () {
|
|
38
|
-
Object.assign(this, Mpx.prototype)
|
|
39
|
-
Object.assign(this, appData)
|
|
40
50
|
const current = this.$root.$options?.router?.currentRoute || {}
|
|
41
51
|
const options = {
|
|
42
52
|
path: current.path && current.path.replace(/^\//, ''),
|
|
@@ -45,48 +55,36 @@ export default function createApp (option, config = {}) {
|
|
|
45
55
|
shareTicket: '',
|
|
46
56
|
referrerInfo: {}
|
|
47
57
|
}
|
|
58
|
+
// web不分冷启动和热启动
|
|
48
59
|
global.__mpxEnterOptions = options
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
if (this.$options.onHide) {
|
|
56
|
-
global.__mpxAppCbs.hide.push(this.$options.onHide.bind(this))
|
|
57
|
-
}
|
|
58
|
-
if (this.$options.onError) {
|
|
59
|
-
global.__mpxAppCbs.error.push(this.$options.onError.bind(this))
|
|
60
|
-
}
|
|
61
|
-
if (this.$options.onUnhandledRejection) {
|
|
62
|
-
global.__mpxAppCbs.rejection.push(this.$options.onUnhandledRejection.bind(this))
|
|
63
|
-
}
|
|
64
|
-
}
|
|
60
|
+
global.__mpxLaunchOptions = options
|
|
61
|
+
rawOptions.onLaunch && rawOptions.onLaunch.call(this, options)
|
|
62
|
+
global.__mpxAppCbs.show.forEach((cb) => {
|
|
63
|
+
cb(options)
|
|
64
|
+
})
|
|
65
65
|
}
|
|
66
66
|
})
|
|
67
67
|
} else {
|
|
68
68
|
builtInMixins.push({
|
|
69
69
|
onLaunch () {
|
|
70
70
|
Object.assign(this, Mpx.prototype)
|
|
71
|
+
initAppProvides(rawOptions.provide, this)
|
|
71
72
|
}
|
|
72
73
|
})
|
|
73
74
|
}
|
|
74
|
-
// app选项目前不需要进行转换
|
|
75
|
-
const { rawOptions, currentInject } = transferOptions(option, 'app', false)
|
|
76
75
|
rawOptions.mixins = builtInMixins
|
|
77
76
|
const defaultOptions = filterOptions(spreadProp(mergeOptions(rawOptions, 'app', false), 'methods'), appData)
|
|
78
77
|
|
|
79
78
|
if (__mpx_mode__ === 'web') {
|
|
80
|
-
global.__mpxOptionsMap = global.__mpxOptionsMap || {}
|
|
81
|
-
global.__mpxOptionsMap[currentInject.moduleId] = defaultOptions
|
|
82
79
|
global.getApp = function () {
|
|
83
80
|
if (!isBrowser) {
|
|
84
81
|
console.error('[Mpx runtime error]: Dangerous API! global.getApp method is running in non browser environments')
|
|
85
82
|
}
|
|
86
83
|
return appData
|
|
87
84
|
}
|
|
85
|
+
global.__mpxOptionsMap = global.__mpxOptionsMap || {}
|
|
86
|
+
global.__mpxOptionsMap[currentInject.moduleId] = defaultOptions
|
|
88
87
|
} else {
|
|
89
|
-
initAppProvides(rawOptions)
|
|
90
88
|
defaultOptions.onAppInit && defaultOptions.onAppInit()
|
|
91
89
|
const ctor = config.customCtor || global.currentCtor || App
|
|
92
90
|
ctor(defaultOptions)
|
|
@@ -11,57 +11,60 @@ function extendEvent (e, extendObj = {}) {
|
|
|
11
11
|
})
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
function
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
this.isTouchDevice = document && ('ontouchstart' in document.documentElement)
|
|
14
|
+
function createMpxEvent (layer) {
|
|
15
|
+
let startTimer = null
|
|
16
|
+
let needTap = true
|
|
17
|
+
let touchStartX = 0
|
|
18
|
+
let touchStartY = 0
|
|
19
|
+
let targetElement = null
|
|
20
|
+
const isTouchDevice = document && 'ontouchstart' in document.documentElement
|
|
22
21
|
|
|
23
|
-
|
|
22
|
+
const onTouchStart = (event) => {
|
|
24
23
|
if (event.targetTouches?.length > 1) {
|
|
25
24
|
return true
|
|
26
25
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
26
|
+
const touches = event.targetTouches
|
|
27
|
+
targetElement = event.target
|
|
28
|
+
needTap = true
|
|
29
|
+
startTimer = null
|
|
30
|
+
touchStartX = touches[0].pageX
|
|
31
|
+
touchStartY = touches[0].pageY
|
|
32
|
+
startTimer = setTimeout(() => {
|
|
33
|
+
needTap = false
|
|
34
|
+
sendEvent(targetElement, 'longpress', event)
|
|
35
|
+
sendEvent(targetElement, 'longtap', event)
|
|
37
36
|
}, 350)
|
|
38
37
|
}
|
|
39
38
|
|
|
40
|
-
|
|
39
|
+
const onTouchMove = (event) => {
|
|
41
40
|
const touch = event.changedTouches[0]
|
|
42
|
-
if (
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
if (
|
|
42
|
+
Math.abs(touch.pageX - touchStartX) > 1 ||
|
|
43
|
+
Math.abs(touch.pageY - touchStartY) > 1
|
|
44
|
+
) {
|
|
45
|
+
needTap = false
|
|
46
|
+
startTimer && clearTimeout(startTimer)
|
|
47
|
+
startTimer = null
|
|
46
48
|
}
|
|
47
49
|
}
|
|
48
50
|
|
|
49
|
-
|
|
51
|
+
const onTouchEnd = (event) => {
|
|
50
52
|
if (event.targetTouches?.length > 1) {
|
|
51
53
|
return true
|
|
52
54
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
if (
|
|
56
|
-
|
|
55
|
+
startTimer && clearTimeout(startTimer)
|
|
56
|
+
startTimer = null
|
|
57
|
+
if (needTap) {
|
|
58
|
+
sendEvent(targetElement, 'tap', event)
|
|
57
59
|
}
|
|
58
60
|
}
|
|
59
61
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
62
|
+
const onClick = (event) => {
|
|
63
|
+
targetElement = event.target
|
|
64
|
+
sendEvent(targetElement, 'tap', event)
|
|
63
65
|
}
|
|
64
|
-
|
|
66
|
+
|
|
67
|
+
const sendEvent = (targetElement, type, event) => {
|
|
65
68
|
const touchEvent = new CustomEvent(type, {
|
|
66
69
|
bubbles: true,
|
|
67
70
|
cancelable: true
|
|
@@ -72,7 +75,6 @@ function MpxEvent (layer) {
|
|
|
72
75
|
changedTouches,
|
|
73
76
|
touches: changedTouches,
|
|
74
77
|
detail: {
|
|
75
|
-
// pc端点击事件可能没有changedTouches,所以直接从 event中取
|
|
76
78
|
x: changedTouches[0]?.pageX || event.pageX || 0,
|
|
77
79
|
y: changedTouches[0]?.pageY || event.pageY || 0
|
|
78
80
|
}
|
|
@@ -80,28 +82,23 @@ function MpxEvent (layer) {
|
|
|
80
82
|
targetElement && targetElement.dispatchEvent(touchEvent)
|
|
81
83
|
}
|
|
82
84
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
layer.addEventListener('click', this.onClick, true)
|
|
90
|
-
}
|
|
85
|
+
if (isTouchDevice) {
|
|
86
|
+
layer.addEventListener('touchstart', onTouchStart, true)
|
|
87
|
+
layer.addEventListener('touchmove', onTouchMove, true)
|
|
88
|
+
layer.addEventListener('touchend', onTouchEnd, true)
|
|
89
|
+
} else {
|
|
90
|
+
layer.addEventListener('click', onClick, true)
|
|
91
91
|
}
|
|
92
|
-
this.addListener()
|
|
93
92
|
}
|
|
94
93
|
|
|
95
94
|
export function initEvent () {
|
|
96
95
|
if (isBrowser && !global.__mpxCreatedEvent) {
|
|
97
96
|
global.__mpxCreatedEvent = true
|
|
98
97
|
if (document.readyState === 'complete' || document.readyState === 'interactive') {
|
|
99
|
-
|
|
100
|
-
new MpxEvent(document.body)
|
|
98
|
+
createMpxEvent(document.body)
|
|
101
99
|
} else {
|
|
102
100
|
document.addEventListener('DOMContentLoaded', function () {
|
|
103
|
-
|
|
104
|
-
new MpxEvent(document.body)
|
|
101
|
+
createMpxEvent(document.body)
|
|
105
102
|
}, false)
|
|
106
103
|
}
|
|
107
104
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isFunction, isNumber, isString } from '@mpxjs/utils'
|
|
1
2
|
import { createI18n } from '../builtInMixins/i18nMixin'
|
|
2
3
|
|
|
3
4
|
export function init (Mpx) {
|
|
@@ -30,21 +31,30 @@ function initGlobalErrorHandling () {
|
|
|
30
31
|
})
|
|
31
32
|
}
|
|
32
33
|
|
|
34
|
+
function onUnhandledRejection (event) {
|
|
35
|
+
if (global.__mpxAppCbs && global.__mpxAppCbs.rejection && global.__mpxAppCbs.rejection.length) {
|
|
36
|
+
global.__mpxAppCbs.rejection.forEach((cb) => {
|
|
37
|
+
cb(event)
|
|
38
|
+
})
|
|
39
|
+
} else {
|
|
40
|
+
console.warn(`UNHANDLED PROMISE REJECTION ${(isNumber(event.id) || isString(event.id)) ? '(id:' + event.id + ')' : ''}: ${event.reason}\n`)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
33
43
|
const rejectionTrackingOptions = {
|
|
34
44
|
allRejections: true,
|
|
35
45
|
onUnhandled (id, error) {
|
|
36
|
-
|
|
37
|
-
global.__mpxAppCbs.rejection.forEach((cb) => {
|
|
38
|
-
cb(error, id)
|
|
39
|
-
})
|
|
40
|
-
} else {
|
|
41
|
-
console.warn(`UNHANDLED PROMISE REJECTION (id: ${id}): ${error}\n`)
|
|
42
|
-
}
|
|
46
|
+
onUnhandledRejection({ id, reason: error, promise: null })
|
|
43
47
|
}
|
|
44
48
|
}
|
|
45
49
|
|
|
46
|
-
|
|
47
|
-
|
|
50
|
+
// 支持 core-js promise polyfill
|
|
51
|
+
const oldOnUnhandledRejection = global.onunhandledrejection
|
|
52
|
+
global.onunhandledrejection = function onunhandledrejection (event) {
|
|
53
|
+
onUnhandledRejection(event)
|
|
54
|
+
isFunction(oldOnUnhandledRejection) && oldOnUnhandledRejection.call(this, event)
|
|
55
|
+
}
|
|
56
|
+
if (global.HermesInternal?.hasPromise?.()) {
|
|
57
|
+
global.HermesInternal.enablePromiseRejectionTracker?.(rejectionTrackingOptions)
|
|
48
58
|
} else {
|
|
49
59
|
require('promise/setimmediate/rejection-tracking').enable(rejectionTrackingOptions)
|
|
50
60
|
}
|
|
@@ -38,7 +38,7 @@ function initGlobalErrorHandling () {
|
|
|
38
38
|
window.addEventListener('unhandledrejection', (event) => {
|
|
39
39
|
if (global.__mpxAppCbs && global.__mpxAppCbs.rejection && global.__mpxAppCbs.rejection.length) {
|
|
40
40
|
global.__mpxAppCbs.rejection.forEach((cb) => {
|
|
41
|
-
cb(event
|
|
41
|
+
cb(event)
|
|
42
42
|
})
|
|
43
43
|
} else {
|
|
44
44
|
console.warn(`UNHANDLED PROMISE REJECTION: ${event.reason}\n`)
|
|
@@ -60,17 +60,23 @@ export default function install (Vue) {
|
|
|
60
60
|
data: {
|
|
61
61
|
get () {
|
|
62
62
|
return Object.assign({}, this.$props, this.$data)
|
|
63
|
-
}
|
|
63
|
+
},
|
|
64
|
+
enumerable: true,
|
|
65
|
+
configurable: true
|
|
64
66
|
},
|
|
65
67
|
dataset: {
|
|
66
68
|
get () {
|
|
67
69
|
return collectDataset(this.$attrs, true)
|
|
68
|
-
}
|
|
70
|
+
},
|
|
71
|
+
enumerable: true,
|
|
72
|
+
configurable: true
|
|
69
73
|
},
|
|
70
74
|
id: {
|
|
71
75
|
get () {
|
|
72
76
|
return this.$attrs.id || ''
|
|
73
|
-
}
|
|
77
|
+
},
|
|
78
|
+
enumerable: true,
|
|
79
|
+
configurable: true
|
|
74
80
|
}
|
|
75
81
|
})
|
|
76
82
|
|
|
@@ -1,39 +1,30 @@
|
|
|
1
1
|
import { callWithErrorHandling, isFunction, isObject, warn } from '@mpxjs/utils'
|
|
2
2
|
import { currentInstance } from '../../core/proxy'
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
__app: Object.create(null),
|
|
7
|
-
/** 页面 scope */
|
|
8
|
-
__pages: Object.create(null)
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
global.__mpxProvidesMap = providesMap
|
|
4
|
+
/** 全局 scope */
|
|
5
|
+
let appProvides = Object.create(null)
|
|
12
6
|
|
|
13
7
|
/** @internal createApp() 初始化应用层 scope provide */
|
|
14
|
-
export function initAppProvides (
|
|
15
|
-
const provideOpt = appOptions.provide
|
|
8
|
+
export function initAppProvides (provideOpt, instance) {
|
|
16
9
|
if (provideOpt) {
|
|
17
10
|
const provided = isFunction(provideOpt)
|
|
18
|
-
? callWithErrorHandling(provideOpt.bind(
|
|
11
|
+
? callWithErrorHandling(provideOpt.bind(instance), instance, 'createApp provide function')
|
|
19
12
|
: provideOpt
|
|
20
13
|
if (isObject(provided)) {
|
|
21
|
-
|
|
14
|
+
appProvides = provided
|
|
22
15
|
} else {
|
|
23
16
|
warn('App provides must be an object or a function that returns an object.')
|
|
24
17
|
}
|
|
25
18
|
}
|
|
26
19
|
}
|
|
27
20
|
|
|
28
|
-
function
|
|
29
|
-
|
|
30
|
-
|
|
21
|
+
function resolveProvides (vm) {
|
|
22
|
+
const provides = vm.provides
|
|
23
|
+
const parentProvides = vm.parent && vm.parent.provides
|
|
24
|
+
if (parentProvides === provides) {
|
|
25
|
+
return (vm.provides = Object.create(parentProvides))
|
|
31
26
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
function resolvePageProvides (context) {
|
|
35
|
-
const pageId = resolvePageId(context)
|
|
36
|
-
return providesMap.__pages[pageId] || (providesMap.__pages[pageId] = Object.create(null))
|
|
27
|
+
return provides
|
|
37
28
|
}
|
|
38
29
|
|
|
39
30
|
export function provide (key, value) {
|
|
@@ -42,8 +33,7 @@ export function provide (key, value) {
|
|
|
42
33
|
warn('provide() can only be used inside setup().')
|
|
43
34
|
return
|
|
44
35
|
}
|
|
45
|
-
|
|
46
|
-
const provides = resolvePageProvides(instance.target)
|
|
36
|
+
const provides = resolveProvides(instance)
|
|
47
37
|
provides[key] = value
|
|
48
38
|
}
|
|
49
39
|
|
|
@@ -53,11 +43,11 @@ export function inject (key, defaultValue, treatDefaultAsFactory = false) {
|
|
|
53
43
|
warn('inject() can only be used inside setup()')
|
|
54
44
|
return
|
|
55
45
|
}
|
|
56
|
-
const provides =
|
|
57
|
-
if (key in provides) {
|
|
46
|
+
const provides = instance.parent && instance.parent.provides
|
|
47
|
+
if (provides && key in provides) {
|
|
58
48
|
return provides[key]
|
|
59
|
-
} else if (key in
|
|
60
|
-
return
|
|
49
|
+
} else if (key in appProvides) {
|
|
50
|
+
return appProvides[key]
|
|
61
51
|
} else if (arguments.length > 1) {
|
|
62
52
|
return treatDefaultAsFactory && isFunction(defaultValue)
|
|
63
53
|
? defaultValue.call(instance && instance.target)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useEffect, useLayoutEffect, useSyncExternalStore, useRef, useMemo, useState, useCallback, createElement, memo, forwardRef, useImperativeHandle, useContext, Fragment, cloneElement } from 'react'
|
|
1
|
+
import { useEffect, useLayoutEffect, useSyncExternalStore, useRef, useMemo, useState, useCallback, createElement, memo, forwardRef, useImperativeHandle, useContext, Fragment, cloneElement, createContext } from 'react'
|
|
2
2
|
import * as ReactNative from 'react-native'
|
|
3
3
|
import { ReactiveEffect } from '../../observer/effect'
|
|
4
4
|
import { watch } from '../../observer/watch'
|
|
@@ -11,6 +11,8 @@ import { queueJob, hasPendingJob } from '../../observer/scheduler'
|
|
|
11
11
|
import { createSelectorQuery, createIntersectionObserver } from '@mpxjs/api-proxy'
|
|
12
12
|
import { IntersectionObserverContext, RouteContext, KeyboardAvoidContext } from '@mpxjs/webpack-plugin/lib/runtime/components/react/dist/context'
|
|
13
13
|
|
|
14
|
+
const ProviderContext = createContext(null)
|
|
15
|
+
|
|
14
16
|
function getSystemInfo () {
|
|
15
17
|
const window = ReactNative.Dimensions.get('window')
|
|
16
18
|
const screen = ReactNative.Dimensions.get('screen')
|
|
@@ -193,7 +195,7 @@ const instanceProto = {
|
|
|
193
195
|
}
|
|
194
196
|
}
|
|
195
197
|
|
|
196
|
-
function createInstance ({ propsRef, type, rawOptions, currentInject, validProps, components, pageId, intersectionCtx }) {
|
|
198
|
+
function createInstance ({ propsRef, type, rawOptions, currentInject, validProps, components, pageId, intersectionCtx, relation, parentProvides }) {
|
|
197
199
|
const instance = Object.create(instanceProto, {
|
|
198
200
|
dataset: {
|
|
199
201
|
get () {
|
|
@@ -244,9 +246,33 @@ function createInstance ({ propsRef, type, rawOptions, currentInject, validProps
|
|
|
244
246
|
return currentInject.getRefsData || noop
|
|
245
247
|
},
|
|
246
248
|
enumerable: false
|
|
249
|
+
},
|
|
250
|
+
__parentProvides: {
|
|
251
|
+
get () {
|
|
252
|
+
return parentProvides || null
|
|
253
|
+
},
|
|
254
|
+
enumerable: false
|
|
247
255
|
}
|
|
248
256
|
})
|
|
249
257
|
|
|
258
|
+
if (type === 'component') {
|
|
259
|
+
Object.defineProperty(instance, '__componentPath', {
|
|
260
|
+
get () {
|
|
261
|
+
return currentInject.componentPath || ''
|
|
262
|
+
},
|
|
263
|
+
enumerable: false
|
|
264
|
+
})
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (relation) {
|
|
268
|
+
Object.defineProperty(instance, '__relation', {
|
|
269
|
+
get () {
|
|
270
|
+
return relation
|
|
271
|
+
},
|
|
272
|
+
enumerable: false
|
|
273
|
+
})
|
|
274
|
+
}
|
|
275
|
+
|
|
250
276
|
// bind this & assign methods
|
|
251
277
|
if (rawOptions.methods) {
|
|
252
278
|
Object.entries(rawOptions.methods).forEach(([key, method]) => {
|
|
@@ -365,34 +391,68 @@ function usePageStatus (navigation, pageId) {
|
|
|
365
391
|
const blurSubscription = navigation.addListener('blur', () => {
|
|
366
392
|
pageStatusMap[pageId] = 'hide'
|
|
367
393
|
})
|
|
368
|
-
const unWatchAppFocusedState = watch(global.__mpxAppFocusedState, (value) => {
|
|
369
|
-
pageStatusMap[pageId] = value
|
|
370
|
-
})
|
|
371
394
|
|
|
372
395
|
return () => {
|
|
373
396
|
focusSubscription()
|
|
374
397
|
blurSubscription()
|
|
375
|
-
unWatchAppFocusedState()
|
|
376
398
|
del(pageStatusMap, pageId)
|
|
377
399
|
}
|
|
378
400
|
}, [navigation])
|
|
379
401
|
}
|
|
380
402
|
|
|
403
|
+
const RelationsContext = createContext(null)
|
|
404
|
+
|
|
405
|
+
const checkRelation = (options) => {
|
|
406
|
+
const relations = options.relations || {}
|
|
407
|
+
let hasDescendantRelation = false
|
|
408
|
+
let hasAncestorRelation = false
|
|
409
|
+
Object.keys(relations).forEach((path) => {
|
|
410
|
+
const relation = relations[path]
|
|
411
|
+
const type = relation.type
|
|
412
|
+
if (['child', 'descendant'].includes(type)) {
|
|
413
|
+
hasDescendantRelation = true
|
|
414
|
+
} else if (['parent', 'ancestor'].includes(type)) {
|
|
415
|
+
hasAncestorRelation = true
|
|
416
|
+
}
|
|
417
|
+
})
|
|
418
|
+
return {
|
|
419
|
+
hasDescendantRelation,
|
|
420
|
+
hasAncestorRelation
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
const provideRelation = (instance, relation) => {
|
|
425
|
+
const componentPath = instance.__componentPath
|
|
426
|
+
if (relation) {
|
|
427
|
+
return Object.assign({}, relation, { [componentPath]: instance })
|
|
428
|
+
} else {
|
|
429
|
+
return {
|
|
430
|
+
[componentPath]: instance
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
381
435
|
export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
|
|
382
436
|
rawOptions = mergeOptions(rawOptions, type, false)
|
|
383
437
|
const components = Object.assign({}, rawOptions.components, currentInject.getComponents())
|
|
384
438
|
const validProps = Object.assign({}, rawOptions.props, rawOptions.properties)
|
|
439
|
+
const { hasDescendantRelation, hasAncestorRelation } = checkRelation(rawOptions)
|
|
385
440
|
if (rawOptions.methods) rawOptions.methods = wrapMethodsWithErrorHandling(rawOptions.methods)
|
|
386
441
|
const defaultOptions = memo(forwardRef((props, ref) => {
|
|
387
442
|
const instanceRef = useRef(null)
|
|
388
443
|
const propsRef = useRef(null)
|
|
389
444
|
const intersectionCtx = useContext(IntersectionObserverContext)
|
|
390
445
|
const pageId = useContext(RouteContext)
|
|
446
|
+
const parentProvides = useContext(ProviderContext)
|
|
447
|
+
let relation = null
|
|
448
|
+
if (hasDescendantRelation || hasAncestorRelation) {
|
|
449
|
+
relation = useContext(RelationsContext)
|
|
450
|
+
}
|
|
391
451
|
propsRef.current = props
|
|
392
452
|
let isFirst = false
|
|
393
453
|
if (!instanceRef.current) {
|
|
394
454
|
isFirst = true
|
|
395
|
-
instanceRef.current = createInstance({ propsRef, type, rawOptions, currentInject, validProps, components, pageId, intersectionCtx })
|
|
455
|
+
instanceRef.current = createInstance({ propsRef, type, rawOptions, currentInject, validProps, components, pageId, intersectionCtx, relation, parentProvides })
|
|
396
456
|
}
|
|
397
457
|
const instance = instanceRef.current
|
|
398
458
|
useImperativeHandle(ref, () => {
|
|
@@ -442,10 +502,17 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
|
|
|
442
502
|
|
|
443
503
|
useEffect(() => {
|
|
444
504
|
if (type === 'page') {
|
|
445
|
-
if (!global.
|
|
505
|
+
if (!global.__mpxAppHotLaunched && global.__mpxAppOnLaunch) {
|
|
446
506
|
global.__mpxAppOnLaunch(props.navigation)
|
|
447
507
|
}
|
|
448
|
-
|
|
508
|
+
const loadParams = {}
|
|
509
|
+
// 此处拿到的props.route.params内属性的value被进行过了一次decode, 不符合预期,此处额外进行一次encode来与微信对齐
|
|
510
|
+
if (isObject(props.route.params)) {
|
|
511
|
+
for (const key in props.route.params) {
|
|
512
|
+
loadParams[key] = encodeURIComponent(props.route.params[key])
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
proxy.callHook(ONLOAD, [loadParams])
|
|
449
516
|
}
|
|
450
517
|
proxy.mounted()
|
|
451
518
|
return () => {
|
|
@@ -470,15 +537,28 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
|
|
|
470
537
|
return proxy.finalMemoVersion
|
|
471
538
|
}, [proxy.stateVersion, proxy.memoVersion])
|
|
472
539
|
|
|
473
|
-
|
|
540
|
+
let root = useMemo(() => proxy.effect.run(), [finalMemoVersion])
|
|
474
541
|
if (root && root.props.ishost) {
|
|
475
542
|
// 对于组件未注册的属性继承到host节点上,如事件、样式和其他属性等
|
|
476
543
|
const rootProps = getRootProps(props, validProps)
|
|
477
544
|
rootProps.style = Object.assign({}, root.props.style, rootProps.style)
|
|
478
545
|
// update root props
|
|
479
|
-
|
|
546
|
+
root = cloneElement(root, rootProps)
|
|
480
547
|
}
|
|
481
|
-
|
|
548
|
+
|
|
549
|
+
const provides = proxy.provides
|
|
550
|
+
if (provides) {
|
|
551
|
+
root = createElement(ProviderContext.Provider, { value: provides }, root)
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
return hasDescendantRelation
|
|
555
|
+
? createElement(RelationsContext.Provider,
|
|
556
|
+
{
|
|
557
|
+
value: provideRelation(instance, relation)
|
|
558
|
+
},
|
|
559
|
+
root
|
|
560
|
+
)
|
|
561
|
+
: root
|
|
482
562
|
}))
|
|
483
563
|
|
|
484
564
|
if (rawOptions.options?.isCustomText) {
|
|
@@ -23,13 +23,11 @@ function transformProperties (properties) {
|
|
|
23
23
|
} else {
|
|
24
24
|
newFiled = Object.assign({}, rawFiled)
|
|
25
25
|
}
|
|
26
|
-
const rawObserver = rawFiled?.observer
|
|
27
26
|
newFiled.observer = function (value, oldValue) {
|
|
28
27
|
if (this.__mpxProxy) {
|
|
29
28
|
this[key] = value
|
|
30
29
|
this.__mpxProxy.propsUpdated()
|
|
31
30
|
}
|
|
32
|
-
rawObserver && rawObserver.call(this, value, oldValue)
|
|
33
31
|
}
|
|
34
32
|
newProps[key] = newFiled
|
|
35
33
|
})
|