@mpxjs/core 2.9.66 → 2.9.69-beta.0

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 (52) hide show
  1. package/@types/global.d.ts +2 -0
  2. package/@types/index.d.ts +18 -2
  3. package/package.json +19 -7
  4. package/src/convertor/convertor.js +11 -32
  5. package/src/convertor/wxToAli.js +3 -3
  6. package/src/convertor/wxToReact.js +1 -1
  7. package/src/convertor/wxToSwan.js +3 -3
  8. package/src/convertor/wxToWeb.js +3 -3
  9. package/src/core/mergeOptions.js +1 -1
  10. package/src/core/proxy.js +86 -12
  11. package/src/dynamic/dynamicRenderMixin.js +2 -2
  12. package/src/index.js +3 -14
  13. package/src/observer/reactive.js +5 -4
  14. package/src/observer/ref.js +3 -2
  15. package/src/observer/scheduler.js +4 -0
  16. package/src/observer/watch.js +5 -4
  17. package/src/platform/builtInMixins/directiveHelperMixin.ios.js +4 -1
  18. package/src/platform/builtInMixins/styleHelperMixin.ios.js +28 -25
  19. package/src/platform/createApp.ios.js +110 -42
  20. package/src/platform/createApp.js +8 -8
  21. package/src/platform/env/event.js +108 -0
  22. package/src/platform/env/index.ios.js +51 -0
  23. package/src/platform/env/index.js +8 -0
  24. package/src/platform/env/index.web.js +48 -0
  25. package/src/{external → platform/env}/vuePlugin.js +1 -1
  26. package/src/platform/export/index.js +5 -0
  27. package/src/platform/export/index.web.js +3 -1
  28. package/src/platform/export/inject.js +68 -0
  29. package/src/platform/export/inject.web.js +1 -0
  30. package/src/platform/patch/builtInKeysMap.js +2 -0
  31. package/src/platform/patch/{ali/getDefaultOptions.js → getDefaultOptions.ali.js} +19 -6
  32. package/src/platform/patch/{react/getDefaultOptions.ios.js → getDefaultOptions.ios.js} +286 -200
  33. package/src/platform/patch/{wx/getDefaultOptions.js → getDefaultOptions.js} +20 -11
  34. package/src/platform/patch/{web/getDefaultOptions.js → getDefaultOptions.web.js} +9 -7
  35. package/src/platform/patch/index.js +4 -21
  36. package/src/platform/patch/{ali/lifecycle.js → lifecycle/index.ali.js} +2 -0
  37. package/src/platform/patch/lifecycle/index.js +1 -0
  38. package/src/platform/patch/{swan/lifecycle.js → lifecycle/index.swan.js} +2 -0
  39. package/src/platform/patch/{web/lifecycle.js → lifecycle/index.web.js} +4 -0
  40. package/src/platform/patch/{wx/lifecycle.js → lifecycle/index.wx.js} +2 -0
  41. package/src/runtime/createFactory.js +3 -0
  42. package/LICENSE +0 -433
  43. package/src/external/vue.js +0 -1
  44. package/src/external/vue.web.js +0 -6
  45. package/src/platform/builtInMixins/directiveHelperMixin.android.js +0 -2
  46. package/src/platform/builtInMixins/proxyEventMixin.android.js +0 -2
  47. package/src/platform/builtInMixins/refsMixin.android.js +0 -2
  48. package/src/platform/builtInMixins/styleHelperMixin.android.js +0 -2
  49. package/src/platform/createApp.android.js +0 -2
  50. package/src/platform/patch/react/getDefaultOptions.android.js +0 -1
  51. package/src/platform/patch/react/getDefaultOptions.js +0 -1
  52. package/src/platform/patch/swan/getDefaultOptions.js +0 -34
@@ -1,19 +1,22 @@
1
- import { isObject, isArray, dash2hump, isFunction, cached, getFocusedNavigation } from '@mpxjs/utils'
1
+ import { isObject, isArray, dash2hump, cached, isEmptyObject } from '@mpxjs/utils'
2
2
  import { Dimensions, StyleSheet } from 'react-native'
3
3
 
4
+ let { width, height } = Dimensions.get('screen')
5
+
6
+ Dimensions.addEventListener('change', ({ screen }) => {
7
+ width = screen.width
8
+ height = screen.height
9
+ })
10
+
4
11
  function rpx (value) {
5
- const { width } = Dimensions.get('screen')
6
12
  // rn 单位 dp = 1(css)px = 1 物理像素 * pixelRatio(像素比)
7
13
  // px = rpx * (750 / 屏幕宽度)
8
14
  return value * width / 750
9
15
  }
10
16
  function vw (value) {
11
- const { width } = Dimensions.get('screen')
12
17
  return value * width / 100
13
18
  }
14
19
  function vh (value) {
15
- const navigation = getFocusedNavigation()
16
- const height = navigation?.layout?.height || Dimensions.get('screen').height
17
20
  return value * height / 100
18
21
  }
19
22
 
@@ -23,15 +26,18 @@ const unit = {
23
26
  vh
24
27
  }
25
28
 
29
+ const empty = {}
30
+
26
31
  function formatValue (value) {
27
- let matched
28
- if ((matched = numberRegExp.exec(value))) {
29
- value = +matched[1]
30
- } else if ((matched = unitRegExp.exec(value))) {
31
- value = unit[matched[2]](+matched[1])
32
- } else if (hairlineRegExp.test(value)) {
33
- value = StyleSheet.hairlineWidth
32
+ const matched = unitRegExp.exec(value)
33
+ if (matched) {
34
+ if (!matched[2] || matched[2] === 'px') {
35
+ return +matched[1]
36
+ } else {
37
+ return unit[matched[2]](+matched[1])
38
+ }
34
39
  }
40
+ if (hairlineRegExp.test(value)) return StyleSheet.hairlineWidth
35
41
  return value
36
42
  }
37
43
 
@@ -106,8 +112,7 @@ function stringifyDynamicClass (value) {
106
112
 
107
113
  const listDelimiter = /;(?![^(]*[)])/g
108
114
  const propertyDelimiter = /:(.+)/
109
- const unitRegExp = /^\s*(-?\d+(?:\.\d+)?)(rpx|vw|vh)\s*$/
110
- const numberRegExp = /^\s*(-?\d+(\.\d+)?)(px)?\s*$/
115
+ const unitRegExp = /^\s*(-?\d+(?:\.\d+)?)(rpx|vw|vh|px)?\s*$/
111
116
  const hairlineRegExp = /^\s*hairlineWidth\s*$/
112
117
  const varRegExp = /^--/
113
118
 
@@ -164,14 +169,8 @@ export default function styleHelperMixin () {
164
169
  },
165
170
  __getStyle (staticClass, dynamicClass, staticStyle, dynamicStyle, hide) {
166
171
  const result = {}
167
- const classMap = {}
168
- // todo 全局样式在每个页面和组件中生效,以支持全局原子类,后续支持样式模块复用后可考虑移除
169
- if (isFunction(global.__getAppClassMap)) {
170
- Object.assign(classMap, global.__getAppClassMap())
171
- }
172
- if (isFunction(this.__getClassMap)) {
173
- Object.assign(classMap, this.__getClassMap())
174
- }
172
+ const classMap = this.__getClassMap?.() || {}
173
+ const appClassMap = global.__getAppClassMap?.() || {}
175
174
 
176
175
  if (staticClass || dynamicClass) {
177
176
  // todo 当前为了复用小程序unocss产物,暂时进行mpEscape,等后续正式支持unocss后可不进行mpEscape
@@ -179,9 +178,12 @@ export default function styleHelperMixin () {
179
178
  classString.split(/\s+/).forEach((className) => {
180
179
  if (classMap[className]) {
181
180
  Object.assign(result, classMap[className])
182
- } else if (this.props[className] && isObject(this.props[className])) {
181
+ } else if (appClassMap[className]) {
182
+ // todo 全局样式在每个页面和组件中生效,以支持全局原子类,后续支持样式模块复用后可考虑移除
183
+ Object.assign(result, appClassMap[className])
184
+ } else if (this.__props[className] && 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 } from '@mpxjs/utils'
3
+ import { makeMap, spreadProp, parseUrlQuery, 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,17 +31,13 @@ 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 = {}) {
41
38
  const appData = {}
42
39
 
43
- const { NavigationContainer, createNavigationContainerRef, createNativeStackNavigator, SafeAreaProvider } = global.__navigationHelper
40
+ const { NavigationContainer, createStackNavigator, SafeAreaProvider } = global.__navigationHelper
44
41
  // app选项目前不需要进行转换
45
42
  const { rawOptions, currentInject } = transferOptions(option, 'app', false)
46
43
  const defaultOptions = filterOptions(spreadProp(rawOptions, 'methods'), appData)
@@ -51,16 +48,25 @@ export default function createApp (option, config = {}) {
51
48
  }
52
49
  const pages = currentInject.getPages() || {}
53
50
  const firstPage = currentInject.firstPage
54
- const Stack = createNativeStackNavigator()
55
- const navigationRef = createNavigationContainerRef()
56
- const pageScreens = Object.entries(pages).map(([key, item]) => {
57
- return createElement(Stack.Screen, {
58
- name: key,
59
- component: item
51
+ const Stack = createStackNavigator()
52
+ const getPageScreens = (initialRouteName, initialParams) => {
53
+ return Object.entries(pages).map(([key, item]) => {
54
+ if (key === initialRouteName) {
55
+ return createElement(Stack.Screen, {
56
+ name: key,
57
+ component: item,
58
+ initialParams
59
+ })
60
+ }
61
+ return createElement(Stack.Screen, {
62
+ name: key,
63
+ component: item
64
+ })
60
65
  })
61
- })
66
+ }
62
67
  global.__mpxOptionsMap = global.__mpxOptionsMap || {}
63
- const onStateChange = () => {
68
+ const onStateChange = (state) => {
69
+ Mpx.config.rnConfig.onStateChange?.(state)
64
70
  if (global.__navigationHelper.lastSuccessCallback) {
65
71
  global.__navigationHelper.lastSuccessCallback()
66
72
  global.__navigationHelper.lastSuccessCallback = null
@@ -75,32 +81,48 @@ export default function createApp (option, config = {}) {
75
81
  }
76
82
  }
77
83
 
78
- global.__mpxAppCbs = global.__mpxAppCbs || {
79
- show: [],
80
- hide: [],
81
- error: []
82
- }
84
+ global.__mpxAppLaunched = false
83
85
 
84
86
  global.__mpxAppFocusedState = ref('show')
85
- global.__mpxOptionsMap[currentInject.moduleId] = memo(() => {
87
+ global.__mpxOptionsMap[currentInject.moduleId] = memo((props) => {
86
88
  const instanceRef = useRef(null)
87
89
  if (!instanceRef.current) {
88
90
  instanceRef.current = createAppInstance(appData)
89
91
  }
90
92
  const instance = instanceRef.current
91
- useEffect(() => {
92
- const current = navigationRef.isReady() ? navigationRef.getCurrentRoute() : {}
93
- const options = {
94
- path: current.name,
95
- query: current.params,
96
- scene: 0,
97
- shareTicket: '',
98
- referrerInfo: {}
93
+ const initialRouteRef = useRef({
94
+ initialRouteName: firstPage,
95
+ initialParams: {}
96
+ })
97
+
98
+ if (!global.__mpxAppLaunched) {
99
+ const parsed = Mpx.config.rnConfig.parseAppProps?.(props) || {}
100
+ if (parsed.url) {
101
+ const { path, queryObj } = parseUrlQuery(parsed.url)
102
+ Object.assign(initialRouteRef.current, {
103
+ initialRouteName: path.startsWith('/') ? path.slice(1) : path,
104
+ initialParams: queryObj
105
+ })
106
+ }
107
+ global.__mpxAppOnLaunch = (navigation) => {
108
+ global.__mpxAppLaunched = true
109
+ const state = navigation.getState()
110
+ Mpx.config.rnConfig.onStateChange?.(state)
111
+ const current = state.routes[state.index]
112
+ global.__mpxEnterOptions = {
113
+ path: current.name,
114
+ query: current.params,
115
+ scene: 0,
116
+ shareTicket: '',
117
+ referrerInfo: {}
118
+ }
119
+ defaultOptions.onLaunch && defaultOptions.onLaunch.call(instance, global.__mpxEnterOptions)
120
+ defaultOptions.onShow && defaultOptions.onShow.call(instance, global.__mpxEnterOptions)
99
121
  }
100
- global.__mpxEnterOptions = options
101
- defaultOptions.onLaunch && defaultOptions.onLaunch.call(instance, options)
122
+ }
123
+
124
+ useEffect(() => {
102
125
  if (defaultOptions.onShow) {
103
- defaultOptions.onShow.call(instance, options)
104
126
  global.__mpxAppCbs.show.push(defaultOptions.onShow.bind(instance))
105
127
  }
106
128
  if (defaultOptions.onHide) {
@@ -109,18 +131,39 @@ export default function createApp (option, config = {}) {
109
131
  if (defaultOptions.onError) {
110
132
  global.__mpxAppCbs.error.push(defaultOptions.onError.bind(instance))
111
133
  }
134
+ if (defaultOptions.onUnhandledRejection) {
135
+ global.__mpxAppCbs.rejection.push(defaultOptions.onUnhandledRejection.bind(instance))
136
+ }
112
137
 
113
138
  const changeSubscription = ReactNative.AppState.addEventListener('change', (currentState) => {
114
139
  if (currentState === 'active') {
140
+ let options = global.__mpxEnterOptions
141
+ const navigation = getFocusedNavigation()
142
+ if (navigation) {
143
+ const state = navigation.getState()
144
+ const current = state.routes[state.index]
145
+ options = {
146
+ path: current.name,
147
+ query: current.params,
148
+ scene: 0,
149
+ shareTicket: '',
150
+ referrerInfo: {}
151
+ }
152
+ }
115
153
  global.__mpxAppCbs.show.forEach((cb) => {
116
154
  cb(options)
117
155
  })
118
- global.__mpxAppFocusedState.value = 'show'
119
- } else if (currentState === 'inactive') {
156
+ if (navigation && hasOwn(global.__mpxPageStatusMap, navigation.pageId)) {
157
+ global.__mpxPageStatusMap[navigation.pageId] = 'show'
158
+ }
159
+ } else if (currentState === 'inactive' || currentState === 'background') {
120
160
  global.__mpxAppCbs.hide.forEach((cb) => {
121
161
  cb()
122
162
  })
123
- global.__mpxAppFocusedState.value = 'hide'
163
+ const navigation = getFocusedNavigation()
164
+ if (navigation && hasOwn(global.__mpxPageStatusMap, navigation.pageId)) {
165
+ global.__mpxPageStatusMap[navigation.pageId] = 'hide'
166
+ }
124
167
  }
125
168
  })
126
169
 
@@ -130,7 +173,10 @@ export default function createApp (option, config = {}) {
130
173
  const orientation = getOrientation(window)
131
174
  if (orientation === lastOrientation) return
132
175
  lastOrientation = orientation
133
- global.__mpxAppFocusedState.value = `resize${count++}`
176
+ const navigation = getFocusedNavigation()
177
+ if (navigation && hasOwn(global.__mpxPageStatusMap, navigation.pageId)) {
178
+ global.__mpxPageStatusMap[navigation.pageId] = `resize${count++}`
179
+ }
134
180
  })
135
181
  return () => {
136
182
  changeSubscription && changeSubscription.remove()
@@ -138,26 +184,41 @@ export default function createApp (option, config = {}) {
138
184
  }
139
185
  }, [])
140
186
 
187
+ const { initialRouteName, initialParams } = initialRouteRef.current
188
+ const headerBackImageProps = Mpx.config.rnConfig.headerBackImageProps || null
189
+ const navScreenOpts = {
190
+ gestureEnabled: true,
191
+ // 7.x替换headerBackTitleVisible
192
+ // headerBackButtonDisplayMode: 'minimal',
193
+ headerBackTitleVisible: false,
194
+ // 安卓上会出现初始化时闪现导航条的问题
195
+ headerShown: false
196
+ }
197
+ if (headerBackImageProps) {
198
+ navScreenOpts.headerBackImage = () => {
199
+ return createElement(Image, headerBackImageProps)
200
+ }
201
+ }
141
202
  return createElement(SafeAreaProvider,
142
203
  null,
143
204
  createElement(NavigationContainer,
144
205
  {
145
- ref: navigationRef,
146
206
  onStateChange,
147
207
  onUnhandledAction
148
208
  },
149
209
  createElement(Stack.Navigator,
150
210
  {
151
- initialRouteName: firstPage
211
+ initialRouteName,
212
+ screenOptions: navScreenOpts
152
213
  },
153
- ...pageScreens
214
+ ...getPageScreens(initialRouteName, initialParams)
154
215
  )
155
216
  )
156
217
  )
157
218
  })
158
219
 
159
220
  global.getCurrentPages = function () {
160
- const navigation = Object.values(global.__mpxPagesMap || {})[0]?.[1]
221
+ const navigation = getFocusedNavigation()
161
222
  if (navigation) {
162
223
  return navigation.getState().routes.map((route) => {
163
224
  return global.__mpxPagesMap[route.key] && global.__mpxPagesMap[route.key][0]
@@ -165,4 +226,11 @@ export default function createApp (option, config = {}) {
165
226
  }
166
227
  return []
167
228
  }
229
+
230
+ global.setCurrentPageStatus = function (status) {
231
+ const navigation = getFocusedNavigation()
232
+ if (navigation && hasOwn(global.__mpxPageStatusMap, navigation.pageId)) {
233
+ global.__mpxPageStatusMap[navigation.pageId] = status
234
+ }
235
+ }
168
236
  }
@@ -3,10 +3,11 @@ import mergeOptions from '../core/mergeOptions'
3
3
  import builtInKeysMap from './patch/builtInKeysMap'
4
4
  import { makeMap, spreadProp, isBrowser } from '@mpxjs/utils'
5
5
  import { mergeLifecycle } from '../convertor/mergeLifecycle'
6
- import * as webLifecycle from '../platform/patch/web/lifecycle'
6
+ import { LIFECYCLE } from '../platform/patch/lifecycle/index'
7
7
  import Mpx from '../index'
8
+ import { initAppProvides } from './export/inject'
8
9
 
9
- const webAppHooksMap = makeMap(mergeLifecycle(webLifecycle.LIFECYCLE).app)
10
+ const appHooksMap = makeMap(mergeLifecycle(LIFECYCLE).app)
10
11
 
11
12
  function filterOptions (options, appData) {
12
13
  const newOptions = {}
@@ -14,7 +15,7 @@ function filterOptions (options, appData) {
14
15
  if (builtInKeysMap[key]) {
15
16
  return
16
17
  }
17
- if (__mpx_mode__ === 'web' && !webAppHooksMap[key]) {
18
+ if (__mpx_mode__ === 'web' && !appHooksMap[key] && key !== 'provide') {
18
19
  appData[key] = options[key]
19
20
  } else {
20
21
  newOptions[key] = options[key]
@@ -46,11 +47,6 @@ export default function createApp (option, config = {}) {
46
47
  }
47
48
  global.__mpxEnterOptions = options
48
49
  this.$options.onLaunch && this.$options.onLaunch.call(this, options)
49
- global.__mpxAppCbs = global.__mpxAppCbs || {
50
- show: [],
51
- hide: [],
52
- error: []
53
- }
54
50
  if (isBrowser) {
55
51
  if (this.$options.onShow) {
56
52
  this.$options.onShow.call(this, options)
@@ -62,6 +58,9 @@ export default function createApp (option, config = {}) {
62
58
  if (this.$options.onError) {
63
59
  global.__mpxAppCbs.error.push(this.$options.onError.bind(this))
64
60
  }
61
+ if (this.$options.onUnhandledRejection) {
62
+ global.__mpxAppCbs.rejection.push(this.$options.onUnhandledRejection.bind(this))
63
+ }
65
64
  }
66
65
  }
67
66
  })
@@ -87,6 +86,7 @@ export default function createApp (option, config = {}) {
87
86
  return appData
88
87
  }
89
88
  } else {
89
+ initAppProvides(rawOptions)
90
90
  defaultOptions.onAppInit && defaultOptions.onAppInit()
91
91
  const ctor = config.customCtor || global.currentCtor || App
92
92
  ctor(defaultOptions)
@@ -0,0 +1,108 @@
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 MpxEvent (layer) {
15
+ this.targetElement = null
16
+ this.touches = []
17
+ this.touchStartX = 0
18
+ this.touchStartY = 0
19
+ this.startTimer = null
20
+ this.needTap = true
21
+ this.isTouchDevice = document && ('ontouchstart' in document.documentElement)
22
+
23
+ this.onTouchStart = (event) => {
24
+ if (event.targetTouches?.length > 1) {
25
+ return true
26
+ }
27
+ this.touches = event.targetTouches
28
+ this.targetElement = event.target
29
+ this.needTap = true
30
+ this.startTimer = null
31
+ this.touchStartX = this.touches[0].pageX
32
+ this.touchStartY = this.touches[0].pageY
33
+ this.startTimer = setTimeout(() => {
34
+ this.needTap = false
35
+ this.sendEvent(this.targetElement, 'longpress', event)
36
+ this.sendEvent(this.targetElement, 'longtap', event)
37
+ }, 350)
38
+ }
39
+
40
+ this.onTouchMove = (event) => {
41
+ const touch = event.changedTouches[0]
42
+ if (Math.abs(touch.pageX - this.touchStartX) > 1 || Math.abs(touch.pageY - this.touchStartY) > 1) {
43
+ this.needTap = false
44
+ this.startTimer && clearTimeout(this.startTimer)
45
+ this.startTimer = null
46
+ }
47
+ }
48
+
49
+ this.onTouchEnd = (event) => {
50
+ if (event.targetTouches?.length > 1) {
51
+ return true
52
+ }
53
+ this.startTimer && clearTimeout(this.startTimer)
54
+ this.startTimer = null
55
+ if (this.needTap) {
56
+ this.sendEvent(this.targetElement, 'tap', event)
57
+ }
58
+ }
59
+
60
+ this.onClick = (event) => {
61
+ this.targetElement = event.target
62
+ this.sendEvent(this.targetElement, 'tap', event)
63
+ }
64
+ this.sendEvent = (targetElement, type, event) => {
65
+ const touchEvent = new CustomEvent(type, {
66
+ bubbles: true,
67
+ cancelable: true
68
+ })
69
+ const changedTouches = event.changedTouches || []
70
+ extendEvent(touchEvent, {
71
+ timeStamp: event.timeStamp,
72
+ changedTouches,
73
+ touches: changedTouches,
74
+ detail: {
75
+ // pc端点击事件可能没有changedTouches,所以直接从 event中取
76
+ x: changedTouches[0]?.pageX || event.pageX || 0,
77
+ y: changedTouches[0]?.pageY || event.pageY || 0
78
+ }
79
+ })
80
+ targetElement && targetElement.dispatchEvent(touchEvent)
81
+ }
82
+
83
+ this.addListener = () => {
84
+ if (this.isTouchDevice) {
85
+ layer.addEventListener('touchstart', this.onTouchStart, true)
86
+ layer.addEventListener('touchmove', this.onTouchMove, true)
87
+ layer.addEventListener('touchend', this.onTouchEnd, true)
88
+ } else {
89
+ layer.addEventListener('click', this.onClick, true)
90
+ }
91
+ }
92
+ this.addListener()
93
+ }
94
+
95
+ export function initEvent () {
96
+ if (isBrowser && !global.__mpxCreatedEvent) {
97
+ global.__mpxCreatedEvent = true
98
+ if (document.readyState === 'complete' || document.readyState === 'interactive') {
99
+ // eslint-disable-next-line no-new
100
+ new MpxEvent(document.body)
101
+ } else {
102
+ document.addEventListener('DOMContentLoaded', function () {
103
+ // eslint-disable-next-line no-new
104
+ new MpxEvent(document.body)
105
+ }, false)
106
+ }
107
+ }
108
+ }
@@ -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,8 @@
1
+ import { createI18n } from '../builtInMixins/i18nMixin'
2
+
3
+ export function init (Mpx) {
4
+ global.__mpx = Mpx
5
+ if (global.i18n) {
6
+ Mpx.i18n = createI18n(global.i18n)
7
+ }
8
+ }
@@ -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 '../helper/const'
4
+ import { PausedState } from '../../helper/const'
5
5
 
6
6
  const hackEffectScope = () => {
7
7
  EffectScope.prototype.pause = function () {
@@ -42,3 +42,8 @@ export {
42
42
  export {
43
43
  useI18n
44
44
  } from '../../platform/builtInMixins/i18nMixin'
45
+
46
+ export {
47
+ provide,
48
+ inject
49
+ } from './inject'
@@ -27,7 +27,9 @@ export {
27
27
  // effectScope
28
28
  effectScope,
29
29
  getCurrentScope,
30
- onScopeDispose
30
+ onScopeDispose,
31
+ provide,
32
+ inject
31
33
  } from 'vue'
32
34
 
33
35
  export {