@mpxjs/core 2.9.70-alpha.0 → 2.9.71
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/@types/global.d.ts +1 -1
- package/LICENSE +433 -0
- package/package.json +9 -6
- package/src/convertor/convertor.js +0 -2
- package/src/convertor/getConvertMode.js +0 -1
- package/src/core/mergeOptions.js +3 -6
- package/src/core/proxy.js +17 -16
- package/src/index.js +3 -14
- package/src/observer/reactive.js +4 -3
- package/src/platform/builtInMixins/directiveHelperMixin.ios.js +4 -1
- package/src/platform/builtInMixins/index.js +0 -5
- package/src/platform/builtInMixins/proxyEventMixin.web.js +53 -5
- package/src/platform/builtInMixins/styleHelperMixin.ios.js +1 -1
- package/src/platform/createApp.ios.js +54 -54
- package/src/platform/createApp.js +26 -37
- package/src/platform/env/event.js +105 -0
- package/src/platform/env/index.ios.js +51 -0
- package/src/platform/env/index.js +8 -0
- package/src/platform/env/index.web.js +48 -0
- package/src/{external → platform/env}/vuePlugin.js +10 -4
- package/src/platform/export/index.js +1 -1
- package/src/platform/export/{apiInject.js → inject.js} +2 -3
- package/src/platform/patch/builtInKeysMap.js +1 -1
- package/src/platform/patch/getDefaultOptions.ios.js +18 -19
- package/src/platform/patch/getDefaultOptions.js +0 -2
- package/src/platform/patch/index.js +3 -3
- package/src/convertor/wxToTenon.js +0 -86
- package/src/external/vue.js +0 -1
- package/src/external/vue.tenon.js +0 -13
- package/src/external/vue.web.js +0 -6
- package/src/platform/builtInMixins/pageStatusMixin.tenon.js +0 -40
- package/src/platform/builtInMixins/proxyEventMixin.tenon.js +0 -46
- package/src/platform/export/apiInject.tenon.js +0 -1
- package/src/platform/export/index.tenon.js +0 -78
- package/src/platform/patch/getDefaultOptions.tenon.js +0 -99
- package/src/platform/patch/lifecycle/index.tenon.js +0 -52
- /package/src/platform/export/{apiInject.web.js → inject.web.js} +0 -0
package/src/observer/reactive.js
CHANGED
|
@@ -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 =
|
|
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 =
|
|
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
|
}
|
|
@@ -37,11 +37,6 @@ export default function getBuiltInMixins ({ type, rawOptions = {} }) {
|
|
|
37
37
|
// 由于relation可能是通过mixin注入的,不能通过当前的用户options中是否存在relations来简单判断是否注入该项mixin
|
|
38
38
|
relationsMixin(type)
|
|
39
39
|
]
|
|
40
|
-
} else if (__mpx_mode__ === 'tenon') {
|
|
41
|
-
bulitInMixins = [
|
|
42
|
-
proxyEventMixin(),
|
|
43
|
-
pageStatusMixin(type)
|
|
44
|
-
]
|
|
45
40
|
} else {
|
|
46
41
|
// 此为差异抹平类mixins,原生模式下也需要注入也抹平平台差异
|
|
47
42
|
bulitInMixins = [
|
|
@@ -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
|
}
|
|
@@ -181,7 +181,7 @@ export default function styleHelperMixin () {
|
|
|
181
181
|
} else if (appClassMap[className]) {
|
|
182
182
|
// todo 全局样式在每个页面和组件中生效,以支持全局原子类,后续支持样式模块复用后可考虑移除
|
|
183
183
|
Object.assign(result, appClassMap[className])
|
|
184
|
-
} else if (
|
|
184
|
+
} else if (isObject(this.__props[className])) {
|
|
185
185
|
// externalClasses必定以对象形式传递下来
|
|
186
186
|
Object.assign(result, this.__props[className])
|
|
187
187
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import transferOptions from '../core/transferOptions'
|
|
2
2
|
import builtInKeysMap from './patch/builtInKeysMap'
|
|
3
|
-
import { makeMap, spreadProp,
|
|
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
|
-
import {
|
|
9
|
+
import { Image } from 'react-native'
|
|
10
10
|
|
|
11
11
|
const appHooksMap = makeMap(mergeLifecycle(LIFECYCLE).app)
|
|
12
12
|
|
|
@@ -29,22 +29,27 @@ function filterOptions (options, appData) {
|
|
|
29
29
|
return newOptions
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
function
|
|
33
|
-
return extend({}, Mpx.prototype, appData)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export default function createApp (option, config = {}) {
|
|
32
|
+
export default function createApp (options) {
|
|
37
33
|
const appData = {}
|
|
38
34
|
|
|
39
35
|
const { NavigationContainer, createStackNavigator, SafeAreaProvider } = global.__navigationHelper
|
|
40
36
|
// app选项目前不需要进行转换
|
|
41
|
-
const { rawOptions, currentInject } = transferOptions(
|
|
37
|
+
const { rawOptions, currentInject } = transferOptions(options, 'app', false)
|
|
42
38
|
const defaultOptions = filterOptions(spreadProp(rawOptions, 'methods'), appData)
|
|
43
|
-
defaultOptions.onAppInit && defaultOptions.onAppInit()
|
|
44
39
|
// 在页面script执行前填充getApp()
|
|
45
40
|
global.getApp = function () {
|
|
46
41
|
return appData
|
|
47
42
|
}
|
|
43
|
+
|
|
44
|
+
// 模拟小程序appInstance在热启动时不会重新创建的行为,在外部创建跟随js context的appInstance
|
|
45
|
+
const appInstance = Object.assign({}, appData, Mpx.prototype)
|
|
46
|
+
|
|
47
|
+
defaultOptions.onShow && global.__mpxAppCbs.show.push(defaultOptions.onShow.bind(appInstance))
|
|
48
|
+
defaultOptions.onHide && global.__mpxAppCbs.hide.push(defaultOptions.onHide.bind(appInstance))
|
|
49
|
+
defaultOptions.onError && global.__mpxAppCbs.error.push(defaultOptions.onError.bind(appInstance))
|
|
50
|
+
defaultOptions.onUnhandledRejection && global.__mpxAppCbs.rejection.push(defaultOptions.onUnhandledRejection.bind(appInstance))
|
|
51
|
+
defaultOptions.onAppInit && defaultOptions.onAppInit()
|
|
52
|
+
|
|
48
53
|
const pages = currentInject.getPages() || {}
|
|
49
54
|
const firstPage = currentInject.firstPage
|
|
50
55
|
const Stack = createStackNavigator()
|
|
@@ -80,63 +85,51 @@ export default function createApp (option, config = {}) {
|
|
|
80
85
|
}
|
|
81
86
|
}
|
|
82
87
|
|
|
83
|
-
global.__mpxAppCbs = global.__mpxAppCbs || {
|
|
84
|
-
show: [],
|
|
85
|
-
hide: [],
|
|
86
|
-
error: []
|
|
87
|
-
}
|
|
88
|
-
|
|
89
88
|
global.__mpxAppLaunched = false
|
|
90
|
-
|
|
91
|
-
global.__mpxAppFocusedState = ref('show')
|
|
92
89
|
global.__mpxOptionsMap[currentInject.moduleId] = memo((props) => {
|
|
93
|
-
const
|
|
94
|
-
if (!instanceRef.current) {
|
|
95
|
-
instanceRef.current = createAppInstance(appData)
|
|
96
|
-
}
|
|
97
|
-
const instance = instanceRef.current
|
|
90
|
+
const firstRef = useRef(true)
|
|
98
91
|
const initialRouteRef = useRef({
|
|
99
92
|
initialRouteName: firstPage,
|
|
100
93
|
initialParams: {}
|
|
101
94
|
})
|
|
95
|
+
if (firstRef.current) {
|
|
96
|
+
// 热启动情况下,app会被销毁重建,将__mpxAppHotLaunched重置保障路由等初始化逻辑正确执行
|
|
97
|
+
global.__mpxAppHotLaunched = false
|
|
98
|
+
// 热启动情况下重置__mpxPagesMap避免页面销毁函数未及时执行时错误地引用到之前的navigation
|
|
99
|
+
global.__mpxPagesMap = {}
|
|
100
|
+
firstRef.current = false
|
|
101
|
+
}
|
|
102
|
+
if (!global.__mpxAppHotLaunched) {
|
|
103
|
+
const { initialRouteName, initialParams } = Mpx.config.rnConfig.parseAppProps?.(props) || {}
|
|
104
|
+
initialRouteRef.current.initialRouteName = initialRouteName || initialRouteRef.current.initialRouteName
|
|
105
|
+
initialRouteRef.current.initialParams = initialParams || initialRouteRef.current.initialParams
|
|
102
106
|
|
|
103
|
-
if (!global.__mpxAppLaunched) {
|
|
104
|
-
const parsed = Mpx.config.rnConfig.parseAppProps?.(props) || {}
|
|
105
|
-
if (parsed.url) {
|
|
106
|
-
const { path, queryObj } = parseUrlQuery(parsed.url)
|
|
107
|
-
Object.assign(initialRouteRef.current, {
|
|
108
|
-
initialRouteName: path.startsWith('/') ? path.slice(1) : path,
|
|
109
|
-
initialParams: queryObj
|
|
110
|
-
})
|
|
111
|
-
}
|
|
112
107
|
global.__mpxAppOnLaunch = (navigation) => {
|
|
113
|
-
global.__mpxAppLaunched = true
|
|
114
108
|
const state = navigation.getState()
|
|
115
109
|
Mpx.config.rnConfig.onStateChange?.(state)
|
|
116
110
|
const current = state.routes[state.index]
|
|
117
|
-
|
|
111
|
+
const options = {
|
|
118
112
|
path: current.name,
|
|
119
113
|
query: current.params,
|
|
120
114
|
scene: 0,
|
|
121
115
|
shareTicket: '',
|
|
122
|
-
referrerInfo: {}
|
|
116
|
+
referrerInfo: {},
|
|
117
|
+
isLaunch: true
|
|
123
118
|
}
|
|
124
|
-
|
|
125
|
-
|
|
119
|
+
global.__mpxEnterOptions = options
|
|
120
|
+
if (!global.__mpxAppLaunched) {
|
|
121
|
+
global.__mpxLaunchOptions = options
|
|
122
|
+
defaultOptions.onLaunch && defaultOptions.onLaunch.call(appInstance, options)
|
|
123
|
+
}
|
|
124
|
+
global.__mpxAppCbs.show.forEach((cb) => {
|
|
125
|
+
cb(options)
|
|
126
|
+
})
|
|
127
|
+
global.__mpxAppLaunched = true
|
|
128
|
+
global.__mpxAppHotLaunched = true
|
|
126
129
|
}
|
|
127
130
|
}
|
|
128
131
|
|
|
129
132
|
useEffect(() => {
|
|
130
|
-
if (defaultOptions.onShow) {
|
|
131
|
-
global.__mpxAppCbs.show.push(defaultOptions.onShow.bind(instance))
|
|
132
|
-
}
|
|
133
|
-
if (defaultOptions.onHide) {
|
|
134
|
-
global.__mpxAppCbs.hide.push(defaultOptions.onHide.bind(instance))
|
|
135
|
-
}
|
|
136
|
-
if (defaultOptions.onError) {
|
|
137
|
-
global.__mpxAppCbs.error.push(defaultOptions.onError.bind(instance))
|
|
138
|
-
}
|
|
139
|
-
|
|
140
133
|
const changeSubscription = ReactNative.AppState.addEventListener('change', (currentState) => {
|
|
141
134
|
if (currentState === 'active') {
|
|
142
135
|
let options = global.__mpxEnterOptions
|
|
@@ -158,7 +151,7 @@ export default function createApp (option, config = {}) {
|
|
|
158
151
|
if (navigation && hasOwn(global.__mpxPageStatusMap, navigation.pageId)) {
|
|
159
152
|
global.__mpxPageStatusMap[navigation.pageId] = 'show'
|
|
160
153
|
}
|
|
161
|
-
} else if (currentState === 'inactive') {
|
|
154
|
+
} else if (currentState === 'inactive' || currentState === 'background') {
|
|
162
155
|
global.__mpxAppCbs.hide.forEach((cb) => {
|
|
163
156
|
cb()
|
|
164
157
|
})
|
|
@@ -187,6 +180,19 @@ export default function createApp (option, config = {}) {
|
|
|
187
180
|
}, [])
|
|
188
181
|
|
|
189
182
|
const { initialRouteName, initialParams } = initialRouteRef.current
|
|
183
|
+
const headerBackImageProps = Mpx.config.rnConfig.headerBackImageProps || null
|
|
184
|
+
const navScreenOpts = {
|
|
185
|
+
// 7.x替换headerBackTitleVisible
|
|
186
|
+
// headerBackButtonDisplayMode: 'minimal',
|
|
187
|
+
headerBackTitleVisible: false,
|
|
188
|
+
// 安卓上会出现初始化时闪现导航条的问题
|
|
189
|
+
headerShown: false
|
|
190
|
+
}
|
|
191
|
+
if (headerBackImageProps) {
|
|
192
|
+
navScreenOpts.headerBackImage = () => {
|
|
193
|
+
return createElement(Image, headerBackImageProps)
|
|
194
|
+
}
|
|
195
|
+
}
|
|
190
196
|
return createElement(SafeAreaProvider,
|
|
191
197
|
null,
|
|
192
198
|
createElement(NavigationContainer,
|
|
@@ -197,13 +203,7 @@ export default function createApp (option, config = {}) {
|
|
|
197
203
|
createElement(Stack.Navigator,
|
|
198
204
|
{
|
|
199
205
|
initialRouteName,
|
|
200
|
-
screenOptions:
|
|
201
|
-
gestureEnabled: true,
|
|
202
|
-
// 7.x替换headerBackTitleVisible
|
|
203
|
-
// headerBackButtonDisplayMode: 'minimal',
|
|
204
|
-
headerBackTitleVisible: false,
|
|
205
|
-
headerMode: 'float'
|
|
206
|
-
}
|
|
206
|
+
screenOptions: navScreenOpts
|
|
207
207
|
},
|
|
208
208
|
...getPageScreens(initialRouteName, initialParams)
|
|
209
209
|
)
|
|
@@ -5,7 +5,7 @@ import { makeMap, spreadProp, isBrowser } from '@mpxjs/utils'
|
|
|
5
5
|
import { mergeLifecycle } from '../convertor/mergeLifecycle'
|
|
6
6
|
import { LIFECYCLE } from '../platform/patch/lifecycle/index'
|
|
7
7
|
import Mpx from '../index'
|
|
8
|
-
import { initAppProvides } from './export/
|
|
8
|
+
import { initAppProvides } from './export/inject'
|
|
9
9
|
|
|
10
10
|
const appHooksMap = makeMap(mergeLifecycle(LIFECYCLE).app)
|
|
11
11
|
|
|
@@ -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,57 +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 (isBrowser) {
|
|
56
|
-
if (this.$options.onShow) {
|
|
57
|
-
this.$options.onShow.call(this, options)
|
|
58
|
-
global.__mpxAppCbs.show.push(this.$options.onShow.bind(this))
|
|
59
|
-
}
|
|
60
|
-
if (this.$options.onHide) {
|
|
61
|
-
global.__mpxAppCbs.hide.push(this.$options.onHide.bind(this))
|
|
62
|
-
}
|
|
63
|
-
if (this.$options.onError) {
|
|
64
|
-
global.__mpxAppCbs.error.push(this.$options.onError.bind(this))
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
})
|
|
69
|
-
} else if (__mpx_mode__ === 'tenon') {
|
|
70
|
-
// todo add tenon mixins
|
|
71
|
-
builtInMixins.push({
|
|
72
|
-
onLaunch () {
|
|
73
|
-
// console.log('tenon mixins')
|
|
60
|
+
global.__mpxLaunchOptions = options
|
|
61
|
+
rawOptions.onLaunch && rawOptions.onLaunch.call(this, options)
|
|
62
|
+
global.__mpxAppCbs.show.forEach((cb) => {
|
|
63
|
+
cb(options)
|
|
64
|
+
})
|
|
74
65
|
}
|
|
75
66
|
})
|
|
76
67
|
} else {
|
|
77
68
|
builtInMixins.push({
|
|
78
69
|
onLaunch () {
|
|
79
70
|
Object.assign(this, Mpx.prototype)
|
|
71
|
+
initAppProvides(rawOptions.provide, this)
|
|
80
72
|
}
|
|
81
73
|
})
|
|
82
74
|
}
|
|
83
|
-
// app选项目前不需要进行转换
|
|
84
|
-
const { rawOptions, currentInject } = transferOptions(option, 'app', false)
|
|
85
75
|
rawOptions.mixins = builtInMixins
|
|
86
76
|
const defaultOptions = filterOptions(spreadProp(mergeOptions(rawOptions, 'app', false), 'methods'), appData)
|
|
87
77
|
|
|
88
|
-
if (__mpx_mode__ === 'web'
|
|
89
|
-
global.__mpxOptionsMap = global.__mpxOptionsMap || {}
|
|
90
|
-
global.__mpxOptionsMap[currentInject.moduleId] = defaultOptions
|
|
78
|
+
if (__mpx_mode__ === 'web') {
|
|
91
79
|
global.getApp = function () {
|
|
92
80
|
if (!isBrowser) {
|
|
93
81
|
console.error('[Mpx runtime error]: Dangerous API! global.getApp method is running in non browser environments')
|
|
94
82
|
}
|
|
95
83
|
return appData
|
|
96
84
|
}
|
|
85
|
+
global.__mpxOptionsMap = global.__mpxOptionsMap || {}
|
|
86
|
+
global.__mpxOptionsMap[currentInject.moduleId] = defaultOptions
|
|
97
87
|
} else {
|
|
98
|
-
initAppProvides(rawOptions)
|
|
99
88
|
defaultOptions.onAppInit && defaultOptions.onAppInit()
|
|
100
89
|
const ctor = config.customCtor || global.currentCtor || App
|
|
101
90
|
ctor(defaultOptions)
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { isBrowser } from '@mpxjs/utils'
|
|
2
|
+
|
|
3
|
+
function extendEvent (e, extendObj = {}) {
|
|
4
|
+
Object.keys(extendObj).forEach((key) => {
|
|
5
|
+
Object.defineProperty(e, key, {
|
|
6
|
+
value: extendObj[key],
|
|
7
|
+
enumerable: true,
|
|
8
|
+
configurable: true,
|
|
9
|
+
writable: true
|
|
10
|
+
})
|
|
11
|
+
})
|
|
12
|
+
}
|
|
13
|
+
|
|
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
|
|
21
|
+
|
|
22
|
+
const onTouchStart = (event) => {
|
|
23
|
+
if (event.targetTouches?.length > 1) {
|
|
24
|
+
return true
|
|
25
|
+
}
|
|
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)
|
|
36
|
+
}, 350)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const onTouchMove = (event) => {
|
|
40
|
+
const touch = event.changedTouches[0]
|
|
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
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const onTouchEnd = (event) => {
|
|
52
|
+
if (event.targetTouches?.length > 1) {
|
|
53
|
+
return true
|
|
54
|
+
}
|
|
55
|
+
startTimer && clearTimeout(startTimer)
|
|
56
|
+
startTimer = null
|
|
57
|
+
if (needTap) {
|
|
58
|
+
sendEvent(targetElement, 'tap', event)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const onClick = (event) => {
|
|
63
|
+
targetElement = event.target
|
|
64
|
+
sendEvent(targetElement, 'tap', event)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const sendEvent = (targetElement, type, event) => {
|
|
68
|
+
const touchEvent = new CustomEvent(type, {
|
|
69
|
+
bubbles: true,
|
|
70
|
+
cancelable: true
|
|
71
|
+
})
|
|
72
|
+
const changedTouches = event.changedTouches || []
|
|
73
|
+
extendEvent(touchEvent, {
|
|
74
|
+
timeStamp: event.timeStamp,
|
|
75
|
+
changedTouches,
|
|
76
|
+
touches: changedTouches,
|
|
77
|
+
detail: {
|
|
78
|
+
x: changedTouches[0]?.pageX || event.pageX || 0,
|
|
79
|
+
y: changedTouches[0]?.pageY || event.pageY || 0
|
|
80
|
+
}
|
|
81
|
+
})
|
|
82
|
+
targetElement && targetElement.dispatchEvent(touchEvent)
|
|
83
|
+
}
|
|
84
|
+
|
|
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
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function initEvent () {
|
|
95
|
+
if (isBrowser && !global.__mpxCreatedEvent) {
|
|
96
|
+
global.__mpxCreatedEvent = true
|
|
97
|
+
if (document.readyState === 'complete' || document.readyState === 'interactive') {
|
|
98
|
+
createMpxEvent(document.body)
|
|
99
|
+
} else {
|
|
100
|
+
document.addEventListener('DOMContentLoaded', function () {
|
|
101
|
+
createMpxEvent(document.body)
|
|
102
|
+
}, false)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { createI18n } from '../builtInMixins/i18nMixin'
|
|
2
|
+
|
|
3
|
+
export function init (Mpx) {
|
|
4
|
+
global.__mpx = Mpx
|
|
5
|
+
global.__mpxAppCbs = global.__mpxAppCbs || {
|
|
6
|
+
show: [],
|
|
7
|
+
hide: [],
|
|
8
|
+
error: [],
|
|
9
|
+
rejection: []
|
|
10
|
+
}
|
|
11
|
+
if (global.i18n) {
|
|
12
|
+
Mpx.i18n = createI18n(global.i18n)
|
|
13
|
+
}
|
|
14
|
+
initGlobalErrorHandling()
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function initGlobalErrorHandling () {
|
|
18
|
+
if (global.ErrorUtils) {
|
|
19
|
+
const defaultHandler = global.ErrorUtils.getGlobalHandler()
|
|
20
|
+
global.ErrorUtils.setGlobalHandler((error, isFatal) => {
|
|
21
|
+
if (global.__mpxAppCbs && global.__mpxAppCbs.error && global.__mpxAppCbs.error.length) {
|
|
22
|
+
global.__mpxAppCbs.error.forEach((cb) => {
|
|
23
|
+
cb(error)
|
|
24
|
+
})
|
|
25
|
+
} else if (defaultHandler) {
|
|
26
|
+
defaultHandler(error, isFatal)
|
|
27
|
+
} else {
|
|
28
|
+
console.error(`${error.name}: ${error.message}\n`)
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const rejectionTrackingOptions = {
|
|
34
|
+
allRejections: true,
|
|
35
|
+
onUnhandled (id, error) {
|
|
36
|
+
if (global.__mpxAppCbs && global.__mpxAppCbs.rejection && global.__mpxAppCbs.rejection.length) {
|
|
37
|
+
global.__mpxAppCbs.rejection.forEach((cb) => {
|
|
38
|
+
cb(error, id)
|
|
39
|
+
})
|
|
40
|
+
} else {
|
|
41
|
+
console.warn(`UNHANDLED PROMISE REJECTION (id: ${id}): ${error}\n`)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (global?.HermesInternal?.hasPromise?.()) {
|
|
47
|
+
global.HermesInternal?.enablePromiseRejectionTracker?.(rejectionTrackingOptions)
|
|
48
|
+
} else {
|
|
49
|
+
require('promise/setimmediate/rejection-tracking').enable(rejectionTrackingOptions)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import Vue from 'vue'
|
|
2
|
+
import install from './vuePlugin'
|
|
3
|
+
import { isBrowser, error, warn } from '@mpxjs/utils'
|
|
4
|
+
import { initEvent } from './event'
|
|
5
|
+
|
|
6
|
+
export function init (Mpx) {
|
|
7
|
+
global.__mpx = Mpx
|
|
8
|
+
global.__mpxAppCbs = global.__mpxAppCbs || {
|
|
9
|
+
show: [],
|
|
10
|
+
hide: [],
|
|
11
|
+
error: [],
|
|
12
|
+
rejection: []
|
|
13
|
+
}
|
|
14
|
+
Mpx.__vue = Vue
|
|
15
|
+
Vue.use(install)
|
|
16
|
+
initEvent()
|
|
17
|
+
initGlobalErrorHandling()
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function initGlobalErrorHandling () {
|
|
21
|
+
Vue.config.errorHandler = (e, vm, info) => {
|
|
22
|
+
error(`Unhandled error occurs${info ? ` during execution of [${info}]` : ''}!`, vm?.__mpxProxy?.options.mpxFileResource, e)
|
|
23
|
+
}
|
|
24
|
+
Vue.config.warnHandler = (msg, vm, trace) => {
|
|
25
|
+
warn(msg, vm?.__mpxProxy?.options.mpxFileResource, trace)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (isBrowser) {
|
|
29
|
+
window.addEventListener('error', (event) => {
|
|
30
|
+
if (global.__mpxAppCbs && global.__mpxAppCbs.error && global.__mpxAppCbs.error.length) {
|
|
31
|
+
global.__mpxAppCbs.error.forEach((cb) => {
|
|
32
|
+
cb(event.error)
|
|
33
|
+
})
|
|
34
|
+
} else {
|
|
35
|
+
console.error(`${event.type}: ${event.message}\n`)
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
window.addEventListener('unhandledrejection', (event) => {
|
|
39
|
+
if (global.__mpxAppCbs && global.__mpxAppCbs.rejection && global.__mpxAppCbs.rejection.length) {
|
|
40
|
+
global.__mpxAppCbs.rejection.forEach((cb) => {
|
|
41
|
+
cb(event.reason, event.promise)
|
|
42
|
+
})
|
|
43
|
+
} else {
|
|
44
|
+
console.warn(`UNHANDLED PROMISE REJECTION: ${event.reason}\n`)
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { walkChildren, parseSelector, error, hasOwn, collectDataset } from '@mpxjs/utils'
|
|
2
2
|
import { createSelectorQuery, createIntersectionObserver } from '@mpxjs/api-proxy'
|
|
3
3
|
import { EffectScope } from 'vue'
|
|
4
|
-
import { PausedState } from '
|
|
4
|
+
import { PausedState } from '../../helper/const'
|
|
5
5
|
|
|
6
6
|
const hackEffectScope = () => {
|
|
7
7
|
EffectScope.prototype.pause = function () {
|
|
@@ -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
|
|