@mpxjs/core 2.9.16 → 2.9.19-react.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 (34) hide show
  1. package/@types/index.d.ts +1 -1
  2. package/package.json +3 -3
  3. package/src/convertor/convertor.js +4 -1
  4. package/src/convertor/getConvertMode.js +3 -1
  5. package/src/convertor/wxToReact.js +31 -0
  6. package/src/core/proxy.js +27 -5
  7. package/src/core/transferOptions.js +9 -1
  8. package/src/{vuePlugin.js → external/vuePlugin.js} +1 -15
  9. package/src/index.js +6 -2
  10. package/src/platform/builtInMixins/directiveHelperMixin.android.js +2 -0
  11. package/src/platform/builtInMixins/directiveHelperMixin.ios.js +15 -0
  12. package/src/platform/builtInMixins/directiveHelperMixin.js +3 -0
  13. package/src/platform/builtInMixins/index.js +12 -2
  14. package/src/platform/builtInMixins/proxyEventMixin.android.js +2 -0
  15. package/src/platform/builtInMixins/proxyEventMixin.ios.js +49 -0
  16. package/src/platform/builtInMixins/proxyEventMixin.js +1 -27
  17. package/src/platform/builtInMixins/refsMixin.android.js +2 -0
  18. package/src/platform/builtInMixins/refsMixin.ios.js +311 -0
  19. package/src/platform/builtInMixins/styleHelperMixin.android.js +2 -0
  20. package/src/platform/builtInMixins/styleHelperMixin.ios.js +135 -0
  21. package/src/platform/builtInMixins/styleHelperMixin.js +3 -0
  22. package/src/platform/createApp.js +2 -2
  23. package/src/platform/export/api.web.js +1 -1
  24. package/src/platform/patch/ali/getDefaultOptions.js +4 -4
  25. package/src/platform/patch/index.js +9 -6
  26. package/src/platform/patch/react/getDefaultOptions.android.js +1 -0
  27. package/src/platform/patch/react/getDefaultOptions.ios.js +249 -0
  28. package/src/platform/patch/react/getDefaultOptions.js +1 -0
  29. package/src/platform/patch/react/lifecycle.js +11 -0
  30. package/src/platform/patch/swan/getDefaultOptions.js +1 -1
  31. package/src/platform/patch/web/getDefaultOptions.js +13 -3
  32. package/src/platform/patch/wx/getDefaultOptions.js +1 -1
  33. /package/src/{vue.js → external/vue.js} +0 -0
  34. /package/src/{vue.web.js → external/vue.web.js} +0 -0
package/@types/index.d.ts CHANGED
@@ -262,7 +262,7 @@ interface MpxConfig {
262
262
  ignoreProxyWhiteList: Array<string>
263
263
  observeClassInstance: boolean | Array<AnyConstructor>
264
264
  errorHandler: (e: Error, target: ComponentIns<{}, {}, {}, {}, []>, hookName: string) => any | null
265
- proxyEventHandler: (e: Event) => any | null
265
+ proxyEventHandler: (e: WechatMiniprogram.CustomEvent) => any | null
266
266
  setDataHandler: (data: object, target: ComponentIns<{}, {}, {}, {}, []>) => any | null
267
267
  forceFlushSync: boolean,
268
268
  webRouteConfig: object,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mpxjs/core",
3
- "version": "2.9.16",
3
+ "version": "2.9.19-react.0",
4
4
  "description": "mpx runtime core",
5
5
  "keywords": [
6
6
  "miniprogram",
@@ -19,7 +19,7 @@
19
19
  ],
20
20
  "main": "src/index.js",
21
21
  "dependencies": {
22
- "@mpxjs/utils": "^2.9.1",
22
+ "@mpxjs/utils": "^2.9.19-react.0",
23
23
  "lodash": "^4.1.1",
24
24
  "miniprogram-api-typings": "^3.10.0"
25
25
  },
@@ -47,5 +47,5 @@
47
47
  "url": "https://github.com/didi/mpx/issues"
48
48
  },
49
49
  "sideEffects": false,
50
- "gitHead": "60cfd1708a61c925d5fc08cca0b31a06b2c4c160"
50
+ "gitHead": "a09ab1b994eaf20b1772491709580fe75499e688"
51
51
  }
@@ -11,6 +11,7 @@ import wxToQqRule from './wxToQq'
11
11
  import wxToTtRule from './wxToTt'
12
12
  import wxToDdRule from './wxToDd'
13
13
  import wxToJdRule from './wxToJd'
14
+ import wxToReactRule from './wxToReact'
14
15
 
15
16
  // 根据当前环境获取的默认生命周期信息
16
17
  let lifecycleInfo
@@ -55,7 +56,9 @@ const rulesMap = {
55
56
  wxToQq: { ...defaultConvertRule, ...wxToQqRule },
56
57
  wxToTt: { ...defaultConvertRule, ...wxToTtRule },
57
58
  wxToDd: { ...defaultConvertRule, ...wxToDdRule },
58
- wxToJd: { ...defaultConvertRule, ...wxToJdRule }
59
+ wxToJd: { ...defaultConvertRule, ...wxToJdRule },
60
+ wxToIos: { ...defaultConvertRule, ...wxToReactRule },
61
+ wxToAndroid: { ...defaultConvertRule, ...wxToReactRule }
59
62
  }
60
63
 
61
64
  export function getConvertRule (convertMode) {
@@ -5,7 +5,9 @@ const convertModes = {
5
5
  'wx-qq': 'wxToQq',
6
6
  'wx-tt': 'wxToTt',
7
7
  'wx-jd': 'wxToJd',
8
- 'wx-dd': 'wxToDd'
8
+ 'wx-dd': 'wxToDd',
9
+ 'wx-ios': 'wxToIos',
10
+ 'wx-android': 'wxToAndroid'
9
11
  }
10
12
 
11
13
  export function getConvertMode (srcMode) {
@@ -0,0 +1,31 @@
1
+ import {
2
+ error,
3
+ isDev
4
+ } from '@mpxjs/utils'
5
+ import { implemented } from '../core/implement'
6
+
7
+ // 暂不支持的wx选项,后期需要各种花式支持
8
+ const unsupported = ['relations', 'moved', 'definitionFilter', 'onShareAppMessage', 'options', 'behaviors', 'externalClasses']
9
+
10
+ function convertErrorDesc (key) {
11
+ error(`Options.${key} is not supported in runtime conversion from wx to react native.`, global.currentResource)
12
+ }
13
+
14
+ function notSupportTip (options) {
15
+ unsupported.forEach(key => {
16
+ if (options[key]) {
17
+ if (!implemented[key]) {
18
+ isDev && convertErrorDesc(key)
19
+ delete options[key]
20
+ } else if (implemented[key].remove) {
21
+ delete options[key]
22
+ }
23
+ }
24
+ })
25
+ }
26
+
27
+ export default {
28
+ convert (options) {
29
+ notSupportTip(options)
30
+ }
31
+ }
package/src/core/proxy.js CHANGED
@@ -27,7 +27,8 @@ import {
27
27
  callWithErrorHandling,
28
28
  warn,
29
29
  error,
30
- getEnvObj
30
+ getEnvObj,
31
+ isReact
31
32
  } from '@mpxjs/utils'
32
33
  import {
33
34
  BEFORECREATE,
@@ -124,6 +125,8 @@ export default class MpxProxy {
124
125
  this.forceUpdateAll = false
125
126
  this.currentRenderTask = null
126
127
  this.propsUpdatedFlag = false
128
+ // react专用,正确触发updated钩子
129
+ this.pendingUpdatedFlag = false
127
130
  }
128
131
  this.initApi()
129
132
  }
@@ -144,7 +147,7 @@ export default class MpxProxy {
144
147
  this.state = CREATED
145
148
  this.callHook(CREATED)
146
149
 
147
- if (__mpx_mode__ !== 'web') {
150
+ if (__mpx_mode__ !== 'web' && !isReact) {
148
151
  this.initRender()
149
152
  }
150
153
 
@@ -166,9 +169,9 @@ export default class MpxProxy {
166
169
 
167
170
  mounted () {
168
171
  if (this.state === CREATED) {
169
- this.state = MOUNTED
170
172
  // 用于处理refs等前置工作
171
173
  this.callHook(BEFOREMOUNT)
174
+ this.state = MOUNTED
172
175
  this.callHook(MOUNTED)
173
176
  this.currentRenderTask && this.currentRenderTask.resolve()
174
177
  }
@@ -191,8 +194,8 @@ export default class MpxProxy {
191
194
  this.callHook(BEFOREUNMOUNT)
192
195
  this.scope?.stop()
193
196
  if (this.update) this.update.active = false
194
- this.callHook(UNMOUNTED)
195
197
  this.state = UNMOUNTED
198
+ this.callHook(UNMOUNTED)
196
199
  }
197
200
 
198
201
  isUnmounted () {
@@ -228,7 +231,12 @@ export default class MpxProxy {
228
231
  }
229
232
 
230
233
  initProps () {
231
- this.props = diffAndCloneA(this.target.__getProps(this.options)).clone
234
+ if (isReact) {
235
+ // react模式下props内部对象透传无需深clone,依赖对象深层的数据响应触发子组件更新
236
+ this.props = this.target.__getProps()
237
+ } else {
238
+ this.props = diffAndCloneA(this.target.__getProps(this.options)).clone
239
+ }
232
240
  reactive(this.props)
233
241
  proxy(this.target, this.props, undefined, false, this.createProxyConflictHandler('props'))
234
242
  }
@@ -594,6 +602,20 @@ export default class MpxProxy {
594
602
  this.forceUpdateAll = true
595
603
  }
596
604
 
605
+ if (isReact) {
606
+ // rn中不需要setdata
607
+ this.forceUpdateData = {}
608
+ this.forceUpdateAll = false
609
+ if (this.update) {
610
+ options.sync ? this.update() : queueJob(this.update)
611
+ }
612
+ if (callback) {
613
+ callback = callback.bind(this.target)
614
+ options.sync ? callback() : nextTick(callback)
615
+ }
616
+ return
617
+ }
618
+
597
619
  if (this.effect) {
598
620
  options.sync ? this.effect.run() : this.effect.update()
599
621
  } else {
@@ -7,6 +7,10 @@ export default function transferOptions (options, type, needConvert = true) {
7
7
  let currentInject
8
8
  if (global.currentInject && global.currentInject.moduleId === global.currentModuleId) {
9
9
  currentInject = global.currentInject
10
+ } else {
11
+ currentInject = {
12
+ moduleId: global.currentModuleId
13
+ }
10
14
  }
11
15
  // 文件编译路径
12
16
  options.mpxFileResource = global.currentResource
@@ -18,8 +22,12 @@ export default function transferOptions (options, type, needConvert = true) {
18
22
  // 编译计算属性注入
19
23
  options.computed = Object.assign({}, currentInject.injectComputed, options.computed)
20
24
  }
25
+ if (currentInject && currentInject.injectMethods) {
26
+ // 编译methods注入
27
+ options.methods = Object.assign({}, currentInject.injectMethods, options.methods)
28
+ }
21
29
  if (currentInject && currentInject.injectOptions) {
22
- // 编译option注入,优先微信中的单独配置
30
+ // 编译options注入,优先微信中的单独配置
23
31
  options.options = Object.assign({}, currentInject.injectOptions, options.options)
24
32
  }
25
33
  if (currentInject && currentInject.pageEvents) {
@@ -1,19 +1,5 @@
1
- import { walkChildren, parseSelector, error, hasOwn } from '@mpxjs/utils'
1
+ import { walkChildren, parseSelector, error, collectDataset } from '@mpxjs/utils'
2
2
  import { createSelectorQuery, createIntersectionObserver } from '@mpxjs/api-proxy'
3
- const datasetReg = /^data-(.+)$/
4
-
5
- function collectDataset (attrs) {
6
- const dataset = {}
7
- for (const key in attrs) {
8
- if (hasOwn(attrs, key)) {
9
- const matched = datasetReg.exec(key)
10
- if (matched) {
11
- dataset[matched[1]] = attrs[key]
12
- }
13
- }
14
- }
15
- return dataset
16
- }
17
3
 
18
4
  export default function install (Vue) {
19
5
  Vue.prototype.triggerEvent = function (eventName, eventDetail) {
package/src/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import Vue from './vue'
1
+ import Vue from './external/vue'
2
2
  import { error, diffAndCloneA, hasOwn, makeMap } from '@mpxjs/utils'
3
3
  import { APIs, InstanceAPIs } from './platform/export/api'
4
4
 
@@ -143,7 +143,11 @@ Mpx.config = {
143
143
  hostWhitelists Array 类型 支持h5域名白名单安全校验
144
144
  apiImplementations webview JSSDK接口 例如getlocation
145
145
  */
146
- webviewConfig: {}
146
+ webviewConfig: {},
147
+ /**
148
+ * react-native 相关配置,用于挂载事件等,如 onShareAppMessage
149
+ */
150
+ rnConfig: {}
147
151
  }
148
152
 
149
153
  global.__mpx = Mpx
@@ -0,0 +1,2 @@
1
+ import directiveHelperMixin from './directiveHelperMixin.ios'
2
+ export default directiveHelperMixin
@@ -0,0 +1,15 @@
1
+ import { warn, type } from '@mpxjs/utils'
2
+ export default function directiveHelperMixin () {
3
+ return {
4
+ methods: {
5
+ __getWxKey (item, key) {
6
+ const value = key === '*this' ? item : item[key]
7
+ if (typeof value === 'string' || typeof value === 'number') {
8
+ return value
9
+ } else {
10
+ warn(`wx:key's value should return a string or a number, received: ${type(value)}`, this.__mpxProxy.options.mpxFileResource)
11
+ }
12
+ }
13
+ }
14
+ }
15
+ }
@@ -0,0 +1,3 @@
1
+ export default function directiveHelperMixin () {
2
+ return {}
3
+ }
@@ -10,10 +10,20 @@ import pageScrollMixin from './pageScrollMixin'
10
10
  import componentGenericsMixin from './componentGenericsMixin'
11
11
  import getTabBarMixin from './getTabBarMixin'
12
12
  import pageRouteMixin from './pageRouteMixin'
13
+ import styleHelperMixin from './styleHelperMixin'
14
+ import directiveHelperMixin from './directiveHelperMixin'
15
+ import { isReact } from '@mpxjs/utils'
13
16
 
14
17
  export default function getBuiltInMixins (options, type) {
15
- let bulitInMixins = []
16
- if (__mpx_mode__ === 'web') {
18
+ let bulitInMixins
19
+ if (isReact) {
20
+ bulitInMixins = [
21
+ proxyEventMixin(),
22
+ directiveHelperMixin(),
23
+ styleHelperMixin(),
24
+ refsMixin()
25
+ ]
26
+ } else if (__mpx_mode__ === 'web') {
17
27
  bulitInMixins = [
18
28
  proxyEventMixin(),
19
29
  refsMixin(),
@@ -0,0 +1,2 @@
1
+ import proxyEventMixin from './proxyEventMixin.ios'
2
+ export default proxyEventMixin
@@ -0,0 +1,49 @@
1
+ import { error } from '@mpxjs/utils'
2
+ import Mpx from '../../index'
3
+
4
+ export default function proxyEventMixin () {
5
+ const methods = {
6
+ __invoke (rawEvent, eventConfig = []) {
7
+ if (typeof Mpx.config.proxyEventHandler === 'function') {
8
+ try {
9
+ Mpx.config.proxyEventHandler(rawEvent)
10
+ } catch (e) {
11
+ }
12
+ }
13
+ const location = this.__mpxProxy.options.mpxFileResource
14
+
15
+ let returnedValue
16
+ eventConfig.forEach((item) => {
17
+ const callbackName = item[0]
18
+ if (callbackName) {
19
+ const params = item.length > 1
20
+ ? item.slice(1).map(item => {
21
+ if (item === '__mpx_event__') {
22
+ return rawEvent
23
+ } else {
24
+ return item
25
+ }
26
+ })
27
+ : [rawEvent]
28
+ if (typeof this[callbackName] === 'function') {
29
+ returnedValue = this[callbackName].apply(this, params)
30
+ } else {
31
+ error(`Instance property [${callbackName}] is not function, please check.`, location)
32
+ }
33
+ }
34
+ })
35
+ return returnedValue
36
+ }
37
+ // __model (expr, $event, valuePath = ['value'], filterMethod) {
38
+ // const innerFilter = {
39
+ // trim: val => typeof val === 'string' && val.trim()
40
+ // }
41
+ // const originValue = valuePath.reduce((acc, cur) => acc[cur], $event.detail)
42
+ // const value = filterMethod ? (innerFilter[filterMethod] ? innerFilter[filterMethod](originValue) : typeof this[filterMethod] === 'function' ? this[filterMethod](originValue) : originValue) : originValue
43
+ // setByPath(this, expr, value)
44
+ // }
45
+ }
46
+ return {
47
+ methods
48
+ }
49
+ }
@@ -1,21 +1,6 @@
1
- import { setByPath, error, hasOwn, dash2hump } from '@mpxjs/utils'
1
+ import { setByPath, error, dash2hump, collectDataset } from '@mpxjs/utils'
2
2
  import Mpx from '../../index'
3
3
 
4
- const datasetReg = /^data-(.+)$/
5
-
6
- function collectDataset (props) {
7
- const dataset = {}
8
- for (const key in props) {
9
- if (hasOwn(props, key)) {
10
- const matched = datasetReg.exec(key)
11
- if (matched) {
12
- dataset[matched[1]] = props[key]
13
- }
14
- }
15
- }
16
- return dataset
17
- }
18
-
19
4
  export default function proxyEventMixin () {
20
5
  const methods = {
21
6
  __invoke ($event) {
@@ -27,7 +12,6 @@ export default function proxyEventMixin () {
27
12
  }
28
13
  const location = this.__mpxProxy.options.mpxFileResource
29
14
  const type = $event.type
30
- const emitMode = $event.detail && $event.detail.mpxEmit
31
15
  if (!type) {
32
16
  error('Event object must have [type] property!', location)
33
17
  return
@@ -51,19 +35,9 @@ export default function proxyEventMixin () {
51
35
  let returnedValue
52
36
  curEventConfig.forEach((item) => {
53
37
  const callbackName = item[0]
54
- if (emitMode) {
55
- $event = $event.detail.data
56
- }
57
38
  if (callbackName) {
58
39
  const params = item.length > 1
59
40
  ? item.slice(1).map(item => {
60
- // 暂不支持$event.xxx的写法
61
- // if (/^\$event/.test(item)) {
62
- // this.__mpxTempEvent = $event
63
- // const value = getByPath(this, item.replace('$event', '__mpxTempEvent'))
64
- // // 删除临时变量
65
- // delete this.__mpxTempEvent
66
- // return value
67
41
  if (item === '__mpx_event__') {
68
42
  return $event
69
43
  } else {
@@ -0,0 +1,2 @@
1
+ import refsMixin from './refsMixin.ios'
2
+ export default refsMixin
@@ -0,0 +1,311 @@
1
+ import { BEFORECREATE } from '../../core/innerLifecycle'
2
+ import { noop, isBoolean, dash2hump, warn, collectDataset, hump2dash } from '@mpxjs/utils'
3
+ import { StyleSheet } from 'react-native'
4
+
5
+ const _createSelectorQuery = (runCb) => {
6
+ return {
7
+ exec: (cb = noop) => {
8
+ runCb().then(res => {
9
+ cb(res)
10
+ })
11
+ },
12
+ in: () => {
13
+ warn('please use wx:ref to get NodesRef')
14
+ },
15
+ select: () => {
16
+ warn('please use wx:ref to get NodesRef')
17
+ },
18
+ selectAll: () => {
19
+ warn('please use wx:ref to get NodesRef')
20
+ },
21
+ selectViewport: () => { // 有点难实现,dimension 目前没有暴露相关 api
22
+ warn('please use wx:ref')
23
+ }
24
+ }
25
+ }
26
+
27
+ const flushRefFns = (nodeInstances, fns) => {
28
+ const mountedNodeInstance = nodeInstances
29
+ .map(instance => instance.getNodeInstance())
30
+ .filter(({ nodeRef }) => nodeRef.current) // 如果有 nodeRef,表明目前组件处于挂载中
31
+ if (mountedNodeInstance.length) {
32
+ return Promise.all(mountedNodeInstance.map(instance => flushFns(instance, fns)))
33
+ } else {
34
+ return Promise.resolve(null)
35
+ }
36
+ }
37
+
38
+ const flushFns = (nodeInstance, fns) => {
39
+ return Promise.all(fns.map(fn => fn(nodeInstance))).then((res) => {
40
+ return res.reduce((preVal, curVal) => {
41
+ return Object.assign(preVal, curVal)
42
+ }, {})
43
+ })
44
+ }
45
+
46
+ const wrapFn = (fn) => {
47
+ return (nodeRef) => {
48
+ return new Promise((resolve) => {
49
+ fn(nodeRef, resolve)
50
+ })
51
+ }
52
+ }
53
+
54
+ const getMeasureProps = (measureProps = []) => {
55
+ return wrapFn((nodeInstance, resolve) => {
56
+ const nodeRef = nodeInstance.nodeRef.current
57
+ setTimeout(() => {
58
+ nodeRef.measure(function (x, y, width, height, pageX, pageY) {
59
+ const rectAndSize = {
60
+ width,
61
+ height,
62
+ left: pageX,
63
+ top: pageY,
64
+ right: pageX + width,
65
+ bottom: pageY + height
66
+ }
67
+ const result = measureProps.reduce((preVal, key) => {
68
+ return Object.assign(preVal, { [key]: rectAndSize[key] || 0 })
69
+ }, {})
70
+ resolve(result)
71
+ })
72
+ }, 30) // 延迟,等待组件在rn视图上真正渲染出来
73
+ })
74
+ }
75
+
76
+ const getDataset = (props) => {
77
+ return wrapFn((nodeRef, resolve) => {
78
+ props = nodeRef.props.current
79
+ resolve({
80
+ dataset: collectDataset(props)
81
+ })
82
+ })
83
+ }
84
+
85
+ const getPlainProps = (config) => {
86
+ return wrapFn((nodeRef, resolve) => {
87
+ const res = {}
88
+ const props = nodeRef.props.current
89
+ config.forEach((key) => {
90
+ // props 属性默认不转驼峰,用户写什么格式不会变化,取值做兼容
91
+ res[key] = props[key] || props[hump2dash(key)] || ''
92
+ })
93
+ resolve(res)
94
+ })
95
+ }
96
+
97
+ const getComputedStyle = (config = []) => {
98
+ return wrapFn((nodeRef, resolve) => {
99
+ config = new Set(config)
100
+ const res = {}
101
+ const styles = nodeRef.props.current.style || []
102
+ const defaultStyle = nodeRef.instance.defaultStyle || {}
103
+ const computedStyle = StyleSheet.flatten([defaultStyle, ...styles])
104
+ config.forEach((key) => {
105
+ const humpKey = dash2hump(key)
106
+ // 取 style 的 key 是根据传入的 key 来设置,传什么设置什么 key,只不过取值需要做兼容
107
+ res[key] = computedStyle[key] || computedStyle[humpKey] || ''
108
+ })
109
+
110
+ resolve(res)
111
+ })
112
+ }
113
+
114
+ const getInstanceConfig = (config) => {
115
+ return wrapFn((nodeRef, resolve) => {
116
+ const instance = nodeRef.instance
117
+ resolve({ [config]: instance[config] || {} })
118
+ })
119
+ }
120
+
121
+ const defaultScrollOffset = {
122
+ scrollLeft: 0,
123
+ scrollTop: 0,
124
+ scrollHeight: 0,
125
+ scrollWidth: 0
126
+ }
127
+
128
+ const getScrollOffset = () => {
129
+ return wrapFn((nodeRef, resolve) => {
130
+ const instance = nodeRef.instance
131
+ resolve((instance.scrollOffset && instance.scrollOffset.current) || defaultScrollOffset)
132
+ })
133
+ }
134
+
135
+ // const getScrollOffsetFallback = (cb) => {
136
+ // const res = {
137
+ // scrollLeft: 0,
138
+ // scrollTop: 0,
139
+ // scrollHeight: 0,
140
+ // scrollWidth: 0
141
+ // }
142
+ // cb(res)
143
+ // }
144
+
145
+ const RECT = ['left', 'top', 'right', 'bottom']
146
+ const SIZE = ['width', 'height']
147
+
148
+ function _createNodesRef (nodeRefs = []) {
149
+ const fields = (config, cb = noop) => {
150
+ const plainProps = []
151
+ const measureProps = []
152
+ const computedStyle = []
153
+ const fns = []
154
+
155
+ for (const key in config) {
156
+ const value = config[key]
157
+ if (Array.isArray(value) && value.length) {
158
+ if (key === 'properties') {
159
+ // wx 最终输出的 properties 字段都会转化为驼峰,所以在这里提前处理为最终的字段格式
160
+ plainProps.push(...value.map(v => dash2hump(v)))
161
+ } else if (key === 'computedStyle') {
162
+ const _computedStyle = config.computedStyle
163
+ for (let i = _computedStyle.length - 1; i >= 0; i--) {
164
+ const style = _computedStyle[i]
165
+ if (RECT.includes(style) || SIZE.includes(style)) {
166
+ measureProps.push(style)
167
+ _computedStyle.splice(i, 1)
168
+ }
169
+ }
170
+ if (_computedStyle.length) {
171
+ computedStyle.push(..._computedStyle)
172
+ }
173
+ }
174
+ } else if (isBoolean(value) && value) {
175
+ switch (key) {
176
+ case 'rect':
177
+ measureProps.push(...RECT)
178
+ break
179
+ case 'size':
180
+ measureProps.push(...SIZE)
181
+ break
182
+ case 'scrollOffset':
183
+ fns.push(getScrollOffset())
184
+ break
185
+ case 'dataset':
186
+ fns.push(getDataset())
187
+ break
188
+ case 'node':
189
+ case 'context':
190
+ case 'ref':
191
+ fns.push(getInstanceConfig(key))
192
+ break
193
+ default:
194
+ plainProps.push(key)
195
+ break
196
+ }
197
+ }
198
+ }
199
+
200
+ if (plainProps.length) {
201
+ fns.push(getPlainProps(plainProps))
202
+ }
203
+ if (measureProps.length) {
204
+ const nodeInstance = nodeRefs[0] && nodeRefs[0].getNodeInstance()
205
+ const hasMeasureFn = nodeInstance && nodeInstance.nodeRef.current && nodeInstance.nodeRef.current.measure
206
+ if (hasMeasureFn) {
207
+ fns.push(getMeasureProps(measureProps))
208
+ } else {
209
+ computedStyle.push(...measureProps)
210
+ }
211
+ }
212
+ if (computedStyle.length) {
213
+ fns.push(getComputedStyle(computedStyle))
214
+ }
215
+
216
+ const runCb = () => {
217
+ return flushRefFns(nodeRefs, fns).then((result) => {
218
+ // wx的数据格式:对于具体方法接受到的回调传参,如果获取的 nodeRef 只有一个,那么只需要返回一条数据而不是数组,但是 exec 里面统一都是数组
219
+ cb(result && result.length === 1 ? result[0] : result)
220
+ return result
221
+ })
222
+ }
223
+
224
+ return _createSelectorQuery(runCb)
225
+ }
226
+
227
+ const boundingClientRect = (cb = noop) => {
228
+ const config = {
229
+ id: true,
230
+ dataset: true,
231
+ rect: true,
232
+ size: true
233
+ }
234
+ return fields(config, cb)
235
+ }
236
+
237
+ const context = (cb = noop) => {
238
+ const config = {
239
+ context: true
240
+ }
241
+ return fields(config, cb)
242
+ }
243
+
244
+ const node = (cb = noop) => {
245
+ const config = {
246
+ node: true
247
+ }
248
+ return fields(config, cb)
249
+ }
250
+
251
+ const ref = (cb = noop) => {
252
+ const config = {
253
+ ref: true
254
+ }
255
+ return fields(config, cb)
256
+ }
257
+
258
+ const scrollOffset = (cb = noop) => {
259
+ const config = {
260
+ id: true,
261
+ dataset: true,
262
+ scrollOffset: true
263
+ }
264
+ return fields(config, cb)
265
+ }
266
+
267
+ return {
268
+ fields,
269
+ boundingClientRect,
270
+ context,
271
+ node,
272
+ ref,
273
+ scrollOffset
274
+ }
275
+ }
276
+
277
+ export default function getRefsMixin () {
278
+ return {
279
+ [BEFORECREATE] () {
280
+ this.__refs = {}
281
+ this.$refs = {}
282
+ this.__getRefs()
283
+ },
284
+ methods: {
285
+ __getRefs () {
286
+ const refs = this.__getRefsData() || []
287
+ const target = this
288
+ refs.forEach(({ key, type, all }) => {
289
+ Object.defineProperty(this.$refs, key, {
290
+ enumerable: true,
291
+ configurable: true,
292
+ get () {
293
+ const refs = target.__refs[key] || []
294
+ if (type === 'component') {
295
+ return all ? refs : refs[0]
296
+ } else {
297
+ return _createNodesRef(refs)
298
+ }
299
+ }
300
+ })
301
+ })
302
+ },
303
+ __getRefVal (key) {
304
+ if (!this.__refs[key]) {
305
+ this.__refs[key] = []
306
+ }
307
+ return (instance) => instance && this.__refs[key].push(instance)
308
+ }
309
+ }
310
+ }
311
+ }
@@ -0,0 +1,2 @@
1
+ import styleHelperMixin from './styleHelperMixin.ios'
2
+ export default styleHelperMixin
@@ -0,0 +1,135 @@
1
+ import { isObject, isArray, dash2hump, isFunction } from '@mpxjs/utils'
2
+ import { Dimensions } from 'react-native'
3
+
4
+ function concat (a, b) {
5
+ return a ? b ? (a + ' ' + b) : a : (b || '')
6
+ }
7
+
8
+ function stringifyArray (value) {
9
+ let res = ''
10
+ let classString
11
+ for (let i = 0; i < value.length; i++) {
12
+ if ((classString = stringifyDynamicClass(value[i]))) {
13
+ if (res) res += ' '
14
+ res += classString
15
+ }
16
+ }
17
+ return res
18
+ }
19
+
20
+ function stringifyObject (value) {
21
+ let res = ''
22
+ const keys = Object.keys(value)
23
+ for (let i = 0; i < keys.length; i++) {
24
+ const key = keys[i]
25
+ if (value[key]) {
26
+ if (res) res += ' '
27
+ res += key
28
+ }
29
+ }
30
+ return res
31
+ }
32
+
33
+ function stringifyDynamicClass (value) {
34
+ if (isArray(value)) {
35
+ value = stringifyArray(value)
36
+ } else if (isObject(value)) {
37
+ value = stringifyObject(value)
38
+ }
39
+ return value
40
+ }
41
+
42
+ const listDelimiter = /;(?![^(]*[)])/g
43
+ const propertyDelimiter = /':(.+)'/
44
+ const rpxRegExp = /^\s*(\d+(\.\d+)?)rpx\s*$/
45
+ const pxRegExp = /^\s*(\d+(\.\d+)?)(px)?\s*$/
46
+
47
+ function parseStyleText (cssText) {
48
+ const res = {}
49
+ const arr = cssText.split(listDelimiter)
50
+ for (let i = 0; i < arr.length; i++) {
51
+ const item = arr[i]
52
+ if (item) {
53
+ const tmp = item.split(propertyDelimiter)
54
+ if (tmp.length > 1) {
55
+ const k = dash2hump(tmp[0].trim())
56
+ res[k] = tmp[1].trim()
57
+ }
58
+ }
59
+ }
60
+ return res
61
+ }
62
+
63
+ function normalizeDynamicStyle (value) {
64
+ if (!value) return {}
65
+ if (isArray(value)) {
66
+ return mergeObjectArray(value)
67
+ }
68
+ if (typeof value === 'string') {
69
+ return parseStyleText(value)
70
+ }
71
+ return value
72
+ }
73
+
74
+ function mergeObjectArray (arr) {
75
+ const res = {}
76
+ for (let i = 0; i < arr.length; i++) {
77
+ Object.assign(res, arr[i])
78
+ }
79
+ return res
80
+ }
81
+
82
+ function transformStyleObj (context, styleObj) {
83
+ const keys = Object.keys(styleObj)
84
+ const transformed = {}
85
+ keys.forEach((prop) => {
86
+ // todo 检测不支持的prop
87
+ let value = styleObj[prop]
88
+ let matched
89
+ if ((matched = pxRegExp.exec(value))) {
90
+ value = +matched[1]
91
+ } else if ((matched = rpxRegExp.exec(value))) {
92
+ value = context.__rpx(+matched[1])
93
+ }
94
+ // todo 检测不支持的value
95
+ transformed[prop] = value
96
+ })
97
+ return transformed
98
+ }
99
+
100
+ export default function styleHelperMixin () {
101
+ return {
102
+ methods: {
103
+ __rpx (value) {
104
+ const { width } = Dimensions.get('screen')
105
+ // rn 单位 dp = 1(css)px = 1 物理像素 * pixelRatio(像素比)
106
+ // px = rpx * (750 / 屏幕宽度)
107
+ return value * width / 750
108
+ },
109
+ __getStyle (staticClass, dynamicClass, staticStyle, dynamicStyle, show) {
110
+ const result = []
111
+ if ((staticClass || dynamicClass) && isFunction(this.__getClassMap)) {
112
+ const classMap = this.__getClassMap()
113
+ const classString = concat(staticClass, stringifyDynamicClass(dynamicClass))
114
+ classString.split(' ').forEach((className) => {
115
+ if (classMap[className]) {
116
+ result.push(classMap[className])
117
+ }
118
+ })
119
+ }
120
+
121
+ if (staticStyle || dynamicStyle) {
122
+ const styleObj = Object.assign(parseStyleText(staticStyle), normalizeDynamicStyle(dynamicStyle))
123
+ result.push(transformStyleObj(this, styleObj))
124
+ }
125
+
126
+ if (show === false) {
127
+ result.push({
128
+ display: 'none'
129
+ })
130
+ }
131
+ return result
132
+ }
133
+ }
134
+ }
135
+ }
@@ -0,0 +1,3 @@
1
+ export default function styleHelperMixin () {
2
+ return {}
3
+ }
@@ -76,13 +76,13 @@ export default function createApp (option, config = {}) {
76
76
  })
77
77
  }
78
78
  // app选项目前不需要进行转换
79
- const { rawOptions } = transferOptions(option, 'app', false)
79
+ const { rawOptions, currentInject } = transferOptions(option, 'app', false)
80
80
  rawOptions.mixins = builtInMixins
81
81
  const defaultOptions = filterOptions(spreadProp(mergeOptions(rawOptions, 'app', false), 'methods'), appData)
82
82
 
83
83
  if (__mpx_mode__ === 'web') {
84
84
  global.__mpxOptionsMap = global.__mpxOptionsMap || {}
85
- global.__mpxOptionsMap[global.currentModuleId] = defaultOptions
85
+ global.__mpxOptionsMap[currentInject.moduleId] = defaultOptions
86
86
  global.getApp = function () {
87
87
  if (!isBrowser) {
88
88
  console.error('[Mpx runtime error]: Dangerous API! global.getApp method is running in non browser environments')
@@ -1,4 +1,4 @@
1
- import Vue from '../../vue'
1
+ import Vue from 'vue'
2
2
  import { injectMixins } from '../../core/injectMixins'
3
3
 
4
4
  const vm = new Vue()
@@ -102,14 +102,14 @@ function initProxy (context, rawOptions, currentInject) {
102
102
  }
103
103
  }
104
104
 
105
- export function getDefaultOptions (type, { rawOptions = {}, currentInject }) {
105
+ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
106
106
  const hookNames = type === 'component' ? ['onInit', 'didMount', 'didUnmount'] : ['onLoad', 'onReady', 'onUnload']
107
107
  const rootMixins = [{
108
108
  [hookNames[0]] () {
109
109
  if (rawOptions.__nativeRender__ && this.props) {
110
110
  const validProps = Object.assign({}, rawOptions.props, rawOptions.properties)
111
111
  Object.keys(this.props).forEach((key) => {
112
- if (hasOwn(validProps, key) && typeof this.props[key] !== 'function') {
112
+ if (hasOwn(validProps, key) && !isFunction(this.props[key])) {
113
113
  this.data[key] = this.props[key]
114
114
  }
115
115
  })
@@ -123,7 +123,7 @@ export function getDefaultOptions (type, { rawOptions = {}, currentInject }) {
123
123
  const newData = {}
124
124
  // 微信原生转换支付宝时,每次props更新将其设置进data模拟微信表现
125
125
  Object.keys(nextProps).forEach((key) => {
126
- if (hasOwn(validProps, key) && typeof nextProps[key] !== 'function') {
126
+ if (hasOwn(validProps, key) && !isFunction(nextProps[key])) {
127
127
  const { diff, clone } = diffAndCloneA(nextProps[key], this.props[key])
128
128
  if (diff) newData[key] = clone
129
129
  }
@@ -133,7 +133,7 @@ export function getDefaultOptions (type, { rawOptions = {}, currentInject }) {
133
133
  // 由于支付宝中props透传父级setData的值,此处发生变化的属性实例一定不同,只需浅比较即可确定发生变化的属性
134
134
  // 支付宝appx2.0版本后props传递发生变化,此处获取到的nextProps和this.props以及父组件setData的数据引用都不一致,进行了两次深克隆,此处this.props和nextProps的比对需要用deep diff
135
135
  Object.keys(nextProps).forEach(key => {
136
- if (hasOwn(validProps, key) && typeof nextProps[key] !== 'function') {
136
+ if (hasOwn(validProps, key) && !isFunction(nextProps[key])) {
137
137
  const { diff, clone } = diffAndCloneA(nextProps[key], this.props[key])
138
138
  // 由于支付宝中透传父级setData的值,此处进行深clone后赋值避免父级存储的miniRenderData部分数据在此处被响应化,在子组件对props赋值时触发父组件的render
139
139
  if (diff) this[key] = clone
@@ -4,14 +4,15 @@ import { getDefaultOptions as getWxDefaultOptions } from './wx/getDefaultOptions
4
4
  import { getDefaultOptions as getAliDefaultOptions } from './ali/getDefaultOptions'
5
5
  import { getDefaultOptions as getSwanDefaultOptions } from './swan/getDefaultOptions'
6
6
  import { getDefaultOptions as getWebDefaultOptions } from './web/getDefaultOptions'
7
- import { error } from '@mpxjs/utils'
7
+ import { getDefaultOptions as getReactDefaultOptions } from './react/getDefaultOptions'
8
+ import { error, isReact } from '@mpxjs/utils'
8
9
 
9
10
  export default function createFactory (type) {
10
11
  return (options = {}, { isNative, customCtor, customCtorType } = {}) => {
11
12
  options.__nativeRender__ = !!isNative
12
13
  options.__type__ = type
13
14
  let ctor
14
- if (__mpx_mode__ !== 'web') {
15
+ if (__mpx_mode__ !== 'web' && !isReact) {
15
16
  if (customCtor) {
16
17
  ctor = customCtor
17
18
  customCtorType = customCtorType || type
@@ -39,7 +40,9 @@ export default function createFactory (type) {
39
40
  }
40
41
 
41
42
  let getDefaultOptions
42
- if (__mpx_mode__ === 'web') {
43
+ if (isReact) {
44
+ getDefaultOptions = getReactDefaultOptions
45
+ } else if (__mpx_mode__ === 'web') {
43
46
  getDefaultOptions = getWebDefaultOptions
44
47
  } else if (__mpx_mode__ === 'ali') {
45
48
  getDefaultOptions = getAliDefaultOptions
@@ -56,10 +59,10 @@ export default function createFactory (type) {
56
59
  // 注入内建的mixins, 内建mixin是按原始平台编写的,所以合并规则和rootMixins保持一致
57
60
  // 将合并后的用户定义的rawOptions传入获取当前应该注入的内建mixins
58
61
  rawOptions.mixins = getBuiltInMixins(rawOptions, type)
59
- const defaultOptions = getDefaultOptions(type, { rawOptions, currentInject })
60
- if (__mpx_mode__ === 'web') {
62
+ const defaultOptions = getDefaultOptions({ type, rawOptions, currentInject })
63
+ if (__mpx_mode__ === 'web' || isReact) {
61
64
  global.__mpxOptionsMap = global.__mpxOptionsMap || {}
62
- global.__mpxOptionsMap[global.currentModuleId] = defaultOptions
65
+ global.__mpxOptionsMap[currentInject.moduleId] = defaultOptions
63
66
  } else if (ctor) {
64
67
  return ctor(defaultOptions)
65
68
  }
@@ -0,0 +1 @@
1
+ export { getDefaultOptions } from './getDefaultOptions.ios'
@@ -0,0 +1,249 @@
1
+ import { useEffect, useSyncExternalStore, useRef, createElement, memo, forwardRef, useImperativeHandle } from 'react'
2
+ import * as reactNative from 'react-native'
3
+ import { ReactiveEffect } from '../../../observer/effect'
4
+ import { hasOwn, isFunction, noop, isObject, error, getByPath, collectDataset } from '@mpxjs/utils'
5
+ import MpxProxy from '../../../core/proxy'
6
+ import { BEFOREUPDATE, UPDATED } from '../../../core/innerLifecycle'
7
+ import mergeOptions from '../../../core/mergeOptions'
8
+ import { queueJob } from '../../../observer/scheduler'
9
+
10
+ function getNativeComponent (tagName) {
11
+ return getByPath(reactNative, tagName)
12
+ }
13
+
14
+ function getRootProps (props) {
15
+ const rootProps = {}
16
+ for (const key in props) {
17
+ if (hasOwn(props, key)) {
18
+ const match = /^(bind|catch|capture-bind|capture-catch|style):?(.*?)(?:\.(.*))?$/.exec(key)
19
+ if (match) {
20
+ rootProps[key] = props[key]
21
+ }
22
+ }
23
+ }
24
+ return rootProps
25
+ }
26
+
27
+ function createEffect (proxy, components, props) {
28
+ const update = proxy.update = () => {
29
+ // pre render for props update
30
+ if (proxy.propsUpdatedFlag) {
31
+ proxy.updatePreRender()
32
+ }
33
+ if (proxy.isMounted()) {
34
+ proxy.callHook(BEFOREUPDATE)
35
+ proxy.pendingUpdatedFlag = true
36
+ }
37
+ // eslint-disable-next-line symbol-description
38
+ proxy.stateVersion = Symbol()
39
+ proxy.onStoreChange && proxy.onStoreChange()
40
+ }
41
+ update.id = proxy.uid
42
+ proxy.effect = new ReactiveEffect(() => {
43
+ return proxy.target.__injectedRender(createElement, components, getNativeComponent, getRootProps(props))
44
+ }, () => queueJob(update), proxy.scope)
45
+ }
46
+
47
+ function createInstance ({ propsRef, ref, type, rawOptions, currentInject, validProps, components }) {
48
+ const instance = Object.create({
49
+ setData (data, callback) {
50
+ return this.__mpxProxy.forceUpdate(data, { sync: true }, callback)
51
+ },
52
+ __getProps () {
53
+ const propsData = {}
54
+ const props = propsRef.current
55
+ if (props) {
56
+ Object.keys(props).forEach((key) => {
57
+ if (hasOwn(validProps, key) && !isFunction(props[key])) {
58
+ propsData[key] = props[key]
59
+ }
60
+ })
61
+ }
62
+ return propsData
63
+ },
64
+ __getSlot (name) {
65
+ const { children } = propsRef.current || {}
66
+ if (children) {
67
+ const result = []
68
+ if (Array.isArray(children)) {
69
+ children.forEach(child => {
70
+ if (child && child.props && child.props.slot === name) {
71
+ result.push(child)
72
+ }
73
+ })
74
+ } else {
75
+ if (children && children.props && children.props.slot === name) {
76
+ result.push(children)
77
+ }
78
+ }
79
+ return result.filter(item => {
80
+ if (this.__dispatchedSlotSet.has(item)) {
81
+ return false
82
+ } else {
83
+ this.__dispatchedSlotSet.add(item)
84
+ return true
85
+ }
86
+ })
87
+ }
88
+ return null
89
+ },
90
+ __injectedRender: currentInject.render || noop,
91
+ __getRefsData: currentInject.getRefsData || noop,
92
+ // render helper
93
+ _i (val, fn) {
94
+ let i, l, keys, key
95
+ const result = []
96
+ if (Array.isArray(val) || typeof val === 'string') {
97
+ for (i = 0, l = val.length; i < l; i++) {
98
+ result.push(fn.call(this, val[i], i))
99
+ }
100
+ } else if (typeof val === 'number') {
101
+ for (i = 0; i < val; i++) {
102
+ result.push(fn.call(this, i + 1, i))
103
+ }
104
+ } else if (isObject(val)) {
105
+ keys = Object.keys(val)
106
+ for (i = 0, l = keys.length; i < l; i++) {
107
+ key = keys[i]
108
+ result.push(fn.call(this, val[key], key, i))
109
+ }
110
+ }
111
+ return result
112
+ },
113
+ triggerEvent (eventName, eventDetail) {
114
+ const props = propsRef.current
115
+ const handlerName = eventName.replace(/^./, matched => matched.toUpperCase()).replace(/-([a-z])/g, (match, p1) => p1.toUpperCase())
116
+ const handler = props && (props['bind' + handlerName] || props['catch' + handlerName] || props['capture-bind' + handlerName] || props['capture-catch' + handlerName])
117
+ if (handler && typeof handler === 'function') {
118
+ const timeStamp = +new Date()
119
+ const dataset = collectDataset(props)
120
+ const id = props.id || ''
121
+ const eventObj = {
122
+ type: eventName,
123
+ timeStamp,
124
+ target: {
125
+ id,
126
+ dataset,
127
+ targetDataset: dataset
128
+ },
129
+ currentTarget: {
130
+ id,
131
+ dataset
132
+ },
133
+ detail: eventDetail
134
+ }
135
+ handler.call(this, eventObj)
136
+ }
137
+ },
138
+ selectComponent () {
139
+ error('selectComponent is not supported in react native, please use ref instead')
140
+ },
141
+ selectAllComponents () {
142
+ error('selectAllComponents is not supported in react native, please use ref instead')
143
+ },
144
+ createSelectorQuery () {
145
+ error('createSelectorQuery is not supported in react native, please use ref instead')
146
+ },
147
+ createIntersectionObserver () {
148
+ error('createIntersectionObserver is not supported in react native, please use ref instead')
149
+ },
150
+ ...rawOptions.methods
151
+ }, {
152
+ dataset: {
153
+ get () {
154
+ const props = propsRef.current
155
+ return collectDataset(props)
156
+ },
157
+ enumerable: true
158
+ },
159
+ id: {
160
+ get () {
161
+ const props = propsRef.current
162
+ return props.id
163
+ },
164
+ enumerable: true
165
+ }
166
+ })
167
+
168
+ const proxy = instance.__mpxProxy = new MpxProxy(rawOptions, instance)
169
+ proxy.created()
170
+ Object.assign(proxy, {
171
+ onStoreChange: null,
172
+ // eslint-disable-next-line symbol-description
173
+ stateVersion: Symbol(),
174
+ subscribe: (onStoreChange) => {
175
+ if (!proxy.effect) {
176
+ createEffect(proxy, components, propsRef.current)
177
+ // eslint-disable-next-line symbol-description
178
+ proxy.stateVersion = Symbol()
179
+ }
180
+ proxy.onStoreChange = onStoreChange
181
+ return () => {
182
+ proxy.effect && proxy.effect.stop()
183
+ proxy.effect = null
184
+ proxy.onStoreChange = null
185
+ }
186
+ },
187
+ getSnapshot: () => {
188
+ return proxy.stateVersion
189
+ }
190
+ })
191
+ // react数据响应组件更新管理器
192
+ if (!proxy.effect) {
193
+ createEffect(proxy, components, propsRef.current)
194
+ }
195
+
196
+ return instance
197
+ }
198
+
199
+ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
200
+ rawOptions = mergeOptions(rawOptions, type, false)
201
+ const components = currentInject.getComponents() || {}
202
+ const validProps = Object.assign({}, rawOptions.props, rawOptions.properties)
203
+ return memo(forwardRef((props, ref) => {
204
+ const instanceRef = useRef(null)
205
+ const propsRef = useRef(props)
206
+ let isFirst = false
207
+ if (!instanceRef.current) {
208
+ isFirst = true
209
+ instanceRef.current = createInstance({ propsRef, ref, type, rawOptions, currentInject, validProps, components })
210
+ }
211
+ const instance = instanceRef.current
212
+ // reset instance
213
+ instance.__refs = {}
214
+ instance.__dispatchedSlotSet = new WeakSet()
215
+ useImperativeHandle(ref, () => {
216
+ return instance
217
+ })
218
+ const proxy = instance.__mpxProxy
219
+
220
+ if (!isFirst) {
221
+ // 处理props更新
222
+ propsRef.current = props
223
+ Object.keys(props).forEach(key => {
224
+ if (hasOwn(validProps, key) && !isFunction(props[key])) {
225
+ instance[key] = props[key]
226
+ }
227
+ })
228
+ proxy.propsUpdated()
229
+ }
230
+
231
+ useEffect(() => {
232
+ if (proxy.pendingUpdatedFlag) {
233
+ proxy.pendingUpdatedFlag = false
234
+ proxy.callHook(UPDATED)
235
+ }
236
+ })
237
+
238
+ useEffect(() => {
239
+ proxy.mounted()
240
+ return () => {
241
+ proxy.unmounted()
242
+ }
243
+ }, [])
244
+
245
+ useSyncExternalStore(proxy.subscribe, proxy.getSnapshot)
246
+
247
+ return proxy.effect.run()
248
+ }))
249
+ }
@@ -0,0 +1 @@
1
+ export function getDefaultOptions () {}
@@ -0,0 +1,11 @@
1
+ const COMPONENT_HOOKS = []
2
+
3
+ const PAGE_HOOKS = []
4
+
5
+ const APP_HOOKS = []
6
+
7
+ export const LIFECYCLE = {
8
+ APP_HOOKS,
9
+ PAGE_HOOKS,
10
+ COMPONENT_HOOKS
11
+ }
@@ -1,7 +1,7 @@
1
1
  import mergeOptions from '../../../core/mergeOptions'
2
2
  import { initProxy, filterOptions } from '../wx/getDefaultOptions'
3
3
 
4
- export function getDefaultOptions (type, { rawOptions = {}, currentInject }) {
4
+ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
5
5
  let hookNames = ['attached', 'ready', 'detached']
6
6
  // 当用户传入page作为构造器构造页面时,修改所有关键hooks
7
7
  if (rawOptions.__pageCtor__) {
@@ -3,7 +3,14 @@ import mergeOptions from '../../../core/mergeOptions'
3
3
  import { diffAndCloneA, hasOwn } from '@mpxjs/utils'
4
4
  import { getCurrentInstance as getCurrentVueInstance } from '../../export/index'
5
5
  import MpxProxy, { setCurrentInstance, unsetCurrentInstance } from '../../../core/proxy'
6
- import { BEFORECREATE, BEFOREUPDATE, UPDATED, BEFOREUNMOUNT, UNMOUNTED, SERVERPREFETCH } from '../../../core/innerLifecycle'
6
+ import {
7
+ BEFORECREATE,
8
+ BEFOREUPDATE,
9
+ UPDATED,
10
+ BEFOREUNMOUNT,
11
+ UNMOUNTED,
12
+ SERVERPREFETCH
13
+ } from '../../../core/innerLifecycle'
7
14
 
8
15
  function filterOptions (options) {
9
16
  const newOptions = {}
@@ -37,7 +44,7 @@ function initProxy (context, rawOptions) {
37
44
  }
38
45
  }
39
46
 
40
- export function getDefaultOptions (type, { rawOptions = {} }) {
47
+ export function getDefaultOptions ({ type, rawOptions = {} }) {
41
48
  const rawSetup = rawOptions.setup
42
49
  if (rawSetup) {
43
50
  rawOptions.setup = (props) => {
@@ -78,7 +85,10 @@ export function getDefaultOptions (type, { rawOptions = {} }) {
78
85
  if (this.__mpxProxy) this.__mpxProxy.callHook(BEFOREUNMOUNT)
79
86
  },
80
87
  destroyed () {
81
- if (this.__mpxProxy) this.__mpxProxy.callHook(UNMOUNTED)
88
+ if (this.__mpxProxy) {
89
+ this.__mpxProxy.state = UNMOUNTED
90
+ this.__mpxProxy.callHook(UNMOUNTED)
91
+ }
82
92
  },
83
93
  serverPrefetch () {
84
94
  if (this.__mpxProxy) return this.__mpxProxy.callHook(SERVERPREFETCH)
@@ -141,7 +141,7 @@ export function initProxy (context, rawOptions, currentInject) {
141
141
  }
142
142
  }
143
143
 
144
- export function getDefaultOptions (type, { rawOptions = {}, currentInject }) {
144
+ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
145
145
  let hookNames = ['attached', 'ready', 'detached']
146
146
  // 当用户传入page作为构造器构造页面时,修改所有关键hooks
147
147
  if (rawOptions.__pageCtor__) {
File without changes
File without changes