@mpxjs/core 2.9.69 → 2.9.70-alpha.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 (40) hide show
  1. package/@types/global.d.ts +1 -1
  2. package/package.json +6 -5
  3. package/src/convertor/convertor.js +13 -32
  4. package/src/convertor/getConvertMode.js +1 -0
  5. package/src/convertor/wxToAli.js +3 -3
  6. package/src/convertor/wxToSwan.js +3 -3
  7. package/src/convertor/wxToTenon.js +86 -0
  8. package/src/convertor/wxToWeb.js +3 -3
  9. package/src/core/proxy.js +18 -11
  10. package/src/dynamic/dynamicRenderMixin.js +2 -2
  11. package/src/external/vue.tenon.js +13 -0
  12. package/src/index.js +1 -1
  13. package/src/observer/reactive.js +1 -1
  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/index.js +5 -0
  18. package/src/platform/builtInMixins/pageStatusMixin.tenon.js +40 -0
  19. package/src/platform/builtInMixins/proxyEventMixin.tenon.js +46 -0
  20. package/src/platform/builtInMixins/styleHelperMixin.ios.js +7 -4
  21. package/src/platform/createApp.ios.js +22 -11
  22. package/src/platform/createApp.js +11 -4
  23. package/src/platform/export/apiInject.tenon.js +1 -0
  24. package/src/platform/export/index.tenon.js +78 -0
  25. package/src/platform/patch/builtInKeysMap.js +1 -1
  26. package/src/platform/patch/{ali/getDefaultOptions.js → getDefaultOptions.ali.js} +3 -3
  27. package/src/platform/patch/{react/getDefaultOptions.ios.js → getDefaultOptions.ios.js} +258 -183
  28. package/src/platform/patch/{wx/getDefaultOptions.js → getDefaultOptions.js} +11 -5
  29. package/src/platform/patch/getDefaultOptions.tenon.js +99 -0
  30. package/src/platform/patch/{web/getDefaultOptions.js → getDefaultOptions.web.js} +5 -5
  31. package/src/platform/patch/index.js +4 -21
  32. package/src/platform/patch/{ali/lifecycle.js → lifecycle/index.ali.js} +2 -0
  33. package/src/platform/patch/lifecycle/index.js +1 -0
  34. package/src/platform/patch/{swan/lifecycle.js → lifecycle/index.swan.js} +2 -0
  35. package/src/platform/patch/lifecycle/index.tenon.js +52 -0
  36. package/src/platform/patch/{web/lifecycle.js → lifecycle/index.web.js} +4 -0
  37. package/src/platform/patch/{wx/lifecycle.js → lifecycle/index.wx.js} +2 -0
  38. package/LICENSE +0 -433
  39. package/src/platform/patch/react/getDefaultOptions.js +0 -1
  40. package/src/platform/patch/swan/getDefaultOptions.js +0 -34
@@ -1,5 +1,5 @@
1
1
  // declaration for mpx mode
2
- declare let __mpx_mode__: 'wx' | 'ali' | 'swan' | 'qq' | 'tt' | 'web' | 'dd' | 'qa' | 'jd'
2
+ declare let __mpx_mode__: 'wx' | 'ali' | 'swan' | 'qq' | 'tt' | 'dd' | 'qa' | 'jd' | 'web' | 'tenon'
3
3
 
4
4
  // declaration for mpx env
5
5
  declare let __mpx_env__: string
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mpxjs/core",
3
- "version": "2.9.69",
3
+ "version": "2.9.70-alpha.0",
4
4
  "description": "mpx runtime core",
5
5
  "keywords": [
6
6
  "miniprogram",
@@ -19,15 +19,16 @@
19
19
  ],
20
20
  "main": "src/index.js",
21
21
  "dependencies": {
22
- "@mpxjs/utils": "^2.9.69",
22
+ "@mpxjs/utils": ">=2.9.69-alpha",
23
23
  "lodash": "^4.1.1",
24
24
  "miniprogram-api-typings": "^3.10.0"
25
25
  },
26
26
  "peerDependencies": {
27
27
  "@ant-design/react-native": "^5.1.3",
28
28
  "@d11/react-native-fast-image": "^8.6.12",
29
- "@mpxjs/api-proxy": "^2.9.0",
30
- "@mpxjs/store": "^2.9.0",
29
+ "@hummer/tenon-store": "^1.7.0",
30
+ "@hummer/tenon-vue": "^1.5.1",
31
+ "@mpxjs/store": ">=2.9.0",
31
32
  "@react-navigation/native": "^7.0.3",
32
33
  "@react-navigation/stack": "^7.0.4",
33
34
  "react": "*",
@@ -105,5 +106,5 @@
105
106
  "url": "https://github.com/didi/mpx/issues"
106
107
  },
107
108
  "sideEffects": false,
108
- "gitHead": "e23c51acc4c2ffdd31fcc6c27aae1aed42d1ade2"
109
+ "gitHead": "2d37697869b9bdda3efab92dda8c910b68fd05c0"
109
110
  }
@@ -1,11 +1,9 @@
1
- import * as wxLifecycle from '../platform/patch/wx/lifecycle'
2
- import * as aliLifecycle from '../platform/patch/ali/lifecycle'
3
- import * as webLifecycle from '../platform/patch/web/lifecycle'
4
- import * as swanLifecycle from '../platform/patch/swan/lifecycle'
1
+ import { LIFECYCLE, lifecycleProxyMap, pageMode } from '../platform/patch/lifecycle/index'
5
2
  import { mergeLifecycle } from './mergeLifecycle'
6
- import { error } from '@mpxjs/utils'
3
+ import { error, extend } from '@mpxjs/utils'
7
4
  import wxToAliRule from './wxToAli'
8
5
  import wxToWebRule from './wxToWeb'
6
+ import wxToTenonRule from './wxToTenon'
9
7
  import wxToSwanRule from './wxToSwan'
10
8
  import wxToQqRule from './wxToQq'
11
9
  import wxToTtRule from './wxToTt'
@@ -13,24 +11,6 @@ import wxToDdRule from './wxToDd'
13
11
  import wxToJdRule from './wxToJd'
14
12
  import wxToReactRule from './wxToReact'
15
13
 
16
- // 根据当前环境获取的默认生命周期信息
17
- let lifecycleInfo
18
- let pageMode
19
-
20
- if (__mpx_mode__ === 'web') {
21
- lifecycleInfo = webLifecycle
22
- pageMode = ''
23
- } else if (__mpx_mode__ === 'ali') {
24
- lifecycleInfo = aliLifecycle
25
- pageMode = ''
26
- } else if (__mpx_mode__ === 'swan') {
27
- lifecycleInfo = swanLifecycle
28
- pageMode = 'blend'
29
- } else {
30
- lifecycleInfo = wxLifecycle
31
- pageMode = 'blend'
32
- }
33
-
34
14
  /**
35
15
  * 转换规则包含四点
36
16
  * lifecycle [object] 生命周期
@@ -40,25 +20,26 @@ if (__mpx_mode__ === 'web') {
40
20
  * convert [function] 自定义转换函数, 接收一个options
41
21
  */
42
22
  const defaultConvertRule = {
43
- lifecycle: mergeLifecycle(lifecycleInfo.LIFECYCLE),
44
- lifecycleProxyMap: lifecycleInfo.lifecycleProxyMap,
23
+ lifecycle: mergeLifecycle(LIFECYCLE),
24
+ lifecycleProxyMap: lifecycleProxyMap,
45
25
  pageMode,
46
26
  support: !!pageMode,
47
27
  convert: null
48
28
  }
49
29
 
50
30
  const rulesMap = {
51
- local: { ...defaultConvertRule },
31
+ local: extend({}, defaultConvertRule),
52
32
  default: defaultConvertRule,
53
33
  wxToWeb: wxToWebRule,
34
+ wxToTenon: wxToTenonRule,
54
35
  wxToAli: wxToAliRule,
55
36
  wxToSwan: wxToSwanRule,
56
- wxToQq: { ...defaultConvertRule, ...wxToQqRule },
57
- wxToTt: { ...defaultConvertRule, ...wxToTtRule },
58
- wxToDd: { ...defaultConvertRule, ...wxToDdRule },
59
- wxToJd: { ...defaultConvertRule, ...wxToJdRule },
60
- wxToIos: { ...defaultConvertRule, ...wxToReactRule },
61
- wxToAndroid: { ...defaultConvertRule, ...wxToReactRule }
37
+ wxToQq: extend({}, defaultConvertRule, wxToQqRule),
38
+ wxToTt: extend({}, defaultConvertRule, wxToTtRule),
39
+ wxToDd: extend({}, defaultConvertRule, wxToDdRule),
40
+ wxToJd: extend({}, defaultConvertRule, wxToJdRule),
41
+ wxToIos: extend({}, defaultConvertRule, wxToReactRule),
42
+ wxToAndroid: extend({}, defaultConvertRule, wxToReactRule)
62
43
  }
63
44
 
64
45
  export function getConvertRule (convertMode) {
@@ -1,6 +1,7 @@
1
1
  const convertModes = {
2
2
  'wx-ali': 'wxToAli',
3
3
  'wx-web': 'wxToWeb',
4
+ 'wx-tenon': 'wxToTenon',
4
5
  'wx-swan': 'wxToSwan',
5
6
  'wx-qq': 'wxToQq',
6
7
  'wx-tt': 'wxToTt',
@@ -1,5 +1,5 @@
1
- import * as wxLifecycle from '../platform/patch/wx/lifecycle'
2
- import * as aliLifecycle from '../platform/patch/ali/lifecycle'
1
+ import * as wxLifecycle from '../platform/patch/lifecycle/index.wx'
2
+ import { LIFECYCLE } from '../platform/patch/lifecycle/index'
3
3
  import { mergeLifecycle } from './mergeLifecycle'
4
4
  import { error, hasOwn, isDev } from '@mpxjs/utils'
5
5
  import { implemented } from '../core/implement'
@@ -38,7 +38,7 @@ function notSupportTip (options) {
38
38
 
39
39
  export default {
40
40
  lifecycle: mergeLifecycle(wxLifecycle.LIFECYCLE),
41
- lifecycle2: mergeLifecycle(aliLifecycle.LIFECYCLE),
41
+ lifecycle2: mergeLifecycle(LIFECYCLE),
42
42
  pageMode: 'blend',
43
43
  support: false,
44
44
  lifecycleProxyMap: wxLifecycle.lifecycleProxyMap,
@@ -1,8 +1,8 @@
1
1
  import { error, isDev } from '@mpxjs/utils'
2
2
  import { implemented } from '../core/implement'
3
3
  import { mergeLifecycle } from './mergeLifecycle'
4
- import * as wxLifecycle from '../platform/patch/wx/lifecycle'
5
- import * as swanLifecycle from '../platform/patch/swan/lifecycle'
4
+ import * as wxLifecycle from '../platform/patch/lifecycle/index.wx'
5
+ import { LIFECYCLE } from '../platform/patch/lifecycle/index'
6
6
 
7
7
  const BEHAVIORS_MAP = {
8
8
  'wx://form-field': 'swan://form-field',
@@ -30,7 +30,7 @@ function notSupportTip (options) {
30
30
 
31
31
  export default {
32
32
  lifecycle: mergeLifecycle(wxLifecycle.LIFECYCLE),
33
- lifecycle2: mergeLifecycle(swanLifecycle.LIFECYCLE),
33
+ lifecycle2: mergeLifecycle(LIFECYCLE),
34
34
  pageMode: 'blend',
35
35
  support: true,
36
36
  lifecycleProxyMap: wxLifecycle.lifecycleProxyMap,
@@ -0,0 +1,86 @@
1
+ import * as wxLifecycle from '../platform/patch/lifecycle/index.wx'
2
+ import * as tenonLifecycle from '../platform/patch/lifecycle/index.tenon'
3
+ import { mergeLifecycle } from './mergeLifecycle'
4
+ import { error, isObject, diffAndCloneA, hasOwn } from '@mpxjs/utils'
5
+ import { implemented } from '../core/implement'
6
+ import { CREATED, UNMOUNTED } from '../core/innerLifecycle'
7
+
8
+ // 暂不支持的wx选项,后期需要各种花式支持
9
+ const unsupported = [
10
+ 'moved',
11
+ 'definitionFilter',
12
+ 'onShareAppMessage',
13
+ 'activated',
14
+ 'deactivated',
15
+ 'pageShow',
16
+ 'pageHide',
17
+ 'onPullDownRefresh',
18
+ 'onReachBottom',
19
+ 'onPageScroll',
20
+ 'onTabItemTap',
21
+ 'onResize',
22
+ 'onUnhandledRejection',
23
+ 'onThemeChange'
24
+ ]
25
+
26
+ function convertErrorDesc (key) {
27
+ error(`Options.${key} is not supported in runtime conversion from wx to tenon.`, global.currentResource)
28
+ }
29
+
30
+ function notSupportTip (options) {
31
+ unsupported.forEach(key => {
32
+ if (options[key]) {
33
+ if (!implemented[key]) {
34
+ process.env.NODE_ENV !== 'production' && convertErrorDesc(key)
35
+ delete options[key]
36
+ } else if (implemented[key].remove) {
37
+ delete options[key]
38
+ }
39
+ }
40
+ })
41
+ }
42
+
43
+ export default {
44
+ lifecycle: mergeLifecycle(wxLifecycle.LIFECYCLE),
45
+ lifecycle2: mergeLifecycle(tenonLifecycle.LIFECYCLE),
46
+ pageMode: 'blend',
47
+ // support传递为true以将methods外层的方法函数合入methods中
48
+ support: true,
49
+ // wx输出tenon时额外将onLoad代理到CREATED
50
+ lifecycleProxyMap: Object.assign({}, wxLifecycle.lifecycleProxyMap, {
51
+ [CREATED]: ['created', 'attached', 'onLoad'],
52
+ [UNMOUNTED]: ['destroyed', 'detached', 'onUnload', 'unmounted']
53
+ }),
54
+ convert (options) {
55
+ const props = Object.assign({}, options.properties, options.props)
56
+ if (props) {
57
+ Object.keys(props).forEach(key => {
58
+ const prop = props[key]
59
+ if (prop) {
60
+ if (hasOwn(prop, 'type')) {
61
+ const newProp = {}
62
+ if (hasOwn(prop, 'optionalTypes')) {
63
+ newProp.type = [prop.type, ...prop.optionalTypes]
64
+ } else {
65
+ newProp.type = prop.type
66
+ }
67
+ if (hasOwn(prop, 'value')) {
68
+ // vue中对于引用类型数据需要使用函数返回
69
+ newProp.default = isObject(prop.value)
70
+ ? function propFn () {
71
+ return diffAndCloneA(prop.value).clone
72
+ }
73
+ : prop.value
74
+ }
75
+ props[key] = newProp
76
+ } else {
77
+ props[key] = prop
78
+ }
79
+ }
80
+ })
81
+ options.props = props
82
+ delete options.properties
83
+ }
84
+ notSupportTip(options)
85
+ }
86
+ }
@@ -1,5 +1,5 @@
1
- import * as wxLifecycle from '../platform/patch/wx/lifecycle'
2
- import * as webLifecycle from '../platform/patch/web/lifecycle'
1
+ import * as wxLifecycle from '../platform/patch/lifecycle/index.wx'
2
+ import { LIFECYCLE } from '../platform/patch/lifecycle/index'
3
3
  import { mergeLifecycle } from './mergeLifecycle'
4
4
  import {
5
5
  isObject,
@@ -32,7 +32,7 @@ function notSupportTip (options) {
32
32
 
33
33
  export default {
34
34
  lifecycle: mergeLifecycle(wxLifecycle.LIFECYCLE),
35
- lifecycle2: mergeLifecycle(webLifecycle.LIFECYCLE),
35
+ lifecycle2: mergeLifecycle(LIFECYCLE),
36
36
  pageMode: 'blend',
37
37
  support: true,
38
38
  lifecycleProxyMap: wxLifecycle.lifecycleProxyMap,
package/src/core/proxy.js CHANGED
@@ -1,4 +1,4 @@
1
- import { reactive } from '../observer/reactive'
1
+ import { reactive, shallowReactive } from '../observer/reactive'
2
2
  import { ReactiveEffect, pauseTracking, resetTracking } from '../observer/effect'
3
3
  import { effectScope } from '../platform/export/index'
4
4
  import { watch } from '../observer/watch'
@@ -14,6 +14,8 @@ import {
14
14
  isEmptyObject,
15
15
  isPlainObject,
16
16
  isWeb,
17
+ isReact,
18
+ isTenon,
17
19
  doGetByPath,
18
20
  getByPath,
19
21
  setByPath,
@@ -116,7 +118,7 @@ export default class MpxProxy {
116
118
  this.ignoreProxyMap = makeMap(Mpx.config.ignoreProxyWhiteList)
117
119
  // 收集setup中动态注册的hooks,小程序与web环境都需要
118
120
  this.hooks = {}
119
- if (__mpx_mode__ !== 'web') {
121
+ if (!isWeb && !isTenon) {
120
122
  this.scope = effectScope(true)
121
123
  // props响应式数据代理
122
124
  this.props = {}
@@ -134,8 +136,12 @@ export default class MpxProxy {
134
136
  this.forceUpdateAll = false
135
137
  this.currentRenderTask = null
136
138
  this.propsUpdatedFlag = false
137
- // react专用,正确触发updated钩子
138
- this.pendingUpdatedFlag = false
139
+ if (isReact) {
140
+ // react专用,正确触发updated钩子
141
+ this.pendingUpdatedFlag = false
142
+ this.memoVersion = Symbol()
143
+ this.finalMemoVersion = Symbol()
144
+ }
139
145
  }
140
146
  this.initApi()
141
147
  }
@@ -160,7 +166,7 @@ export default class MpxProxy {
160
166
  // 缓存上下文,在 destoryed 阶段删除
161
167
  contextMap.set(this.uid, this.target)
162
168
  }
163
- if (__mpx_mode__ !== 'web') {
169
+ if (!isWeb && !isTenon) {
164
170
  // web中BEFORECREATE钩子通过vue的beforeCreate钩子单独驱动
165
171
  this.callHook(BEFORECREATE)
166
172
  setCurrentInstance(this)
@@ -179,7 +185,7 @@ export default class MpxProxy {
179
185
  this.state = CREATED
180
186
  this.callHook(CREATED)
181
187
 
182
- if (__mpx_mode__ !== 'web' && __mpx_mode__ !== 'ios' && __mpx_mode__ !== 'android') {
188
+ if (!isWeb && !isReact && !isTenon) {
183
189
  this.initRender()
184
190
  }
185
191
 
@@ -272,7 +278,7 @@ export default class MpxProxy {
272
278
  }
273
279
  // 挂载$rawOptions
274
280
  this.target.$rawOptions = this.options
275
- if (__mpx_mode__ !== 'web') {
281
+ if (!isWeb && !isTenon) {
276
282
  // 挂载$watch
277
283
  this.target.$watch = this.watch.bind(this)
278
284
  // 强制执行render
@@ -282,13 +288,14 @@ export default class MpxProxy {
282
288
  }
283
289
 
284
290
  initProps () {
285
- if (__mpx_mode__ === 'ios' || __mpx_mode__ === 'android') {
291
+ if (isReact) {
286
292
  // react模式下props内部对象透传无需深clone,依赖对象深层的数据响应触发子组件更新
287
293
  this.props = this.target.__getProps()
294
+ shallowReactive(this.processIgnoreReactive(this.props))
288
295
  } else {
289
296
  this.props = diffAndCloneA(this.target.__getProps(this.options)).clone
297
+ reactive(this.processIgnoreReactive(this.props))
290
298
  }
291
- reactive(this.processIgnoreReactive(this.props))
292
299
  proxy(this.target, this.props, undefined, false, this.createProxyConflictHandler('props'))
293
300
  }
294
301
 
@@ -562,7 +569,7 @@ export default class MpxProxy {
562
569
  }
563
570
  if (!processed) {
564
571
  // 如果当前数据和上次的miniRenderData完全无关,但存在于组件的视图数据中,则与组件视图数据进行diff
565
- if (this.target.data && hasOwn(this.target.data, firstKey)) {
572
+ if (hasOwn(this.target.data, firstKey)) {
566
573
  const localInitialData = getByPath(this.target.data, key)
567
574
  const { clone, diff, diffData } = diffAndCloneA(data, localInitialData)
568
575
  this.miniRenderData[key] = clone
@@ -760,7 +767,7 @@ export default class MpxProxy {
760
767
  this.forceUpdateAll = true
761
768
  }
762
769
 
763
- if (__mpx_mode__ === 'ios' || __mpx_mode__ === 'android') {
770
+ if (isReact) {
764
771
  // rn中不需要setdata
765
772
  this.forceUpdateData = {}
766
773
  this.forceUpdateAll = false
@@ -1,4 +1,4 @@
1
- import { hasOwn, isObject, error } from '@mpxjs/utils'
1
+ import { hasOwn, error } from '@mpxjs/utils'
2
2
  import genVnodeTree from './vnode/render'
3
3
  import contextMap from './vnode/context'
4
4
  import { CREATED } from '../core/innerLifecycle'
@@ -56,7 +56,7 @@ function dynamicRenderHelperMixin () {
56
56
  methods: {
57
57
  _g (astData, moduleId) {
58
58
  const location = this.__mpxProxy && this.__mpxProxy.options.mpxFileResource
59
- if (astData && isObject(astData) && hasOwn(astData, 'template')) {
59
+ if (hasOwn(astData, 'template')) {
60
60
  const vnodeTree = genVnodeTree(astData, [this], { moduleId, location })
61
61
  return vnodeTree
62
62
  } else {
@@ -0,0 +1,13 @@
1
+ import {
2
+ reactive,
3
+ computed,
4
+ toRaw,
5
+ watch
6
+ } from '@hummer/tenon-vue'
7
+
8
+ export default {
9
+ reactive,
10
+ computed,
11
+ toRaw,
12
+ watch
13
+ }
package/src/index.js CHANGED
@@ -124,7 +124,7 @@ function factory () {
124
124
  Object.assign(Mpx, APIs)
125
125
  Object.assign(Mpx.prototype, InstanceAPIs)
126
126
  // 输出web时在mpx上挂载Vue对象
127
- if (__mpx_mode__ === 'web') {
127
+ if (__mpx_mode__ === 'web' || __mpx_mode__ === 'tenon') {
128
128
  Mpx.__vue = Vue
129
129
  }
130
130
  return Mpx
@@ -225,7 +225,7 @@ export function shallowReactive (value) {
225
225
  }
226
226
 
227
227
  export function isReactive (value) {
228
- return value && hasOwn(value, ObKey) && value[ObKey] instanceof Observer
228
+ return hasOwn(value, ObKey) && value[ObKey] instanceof Observer
229
229
  }
230
230
 
231
231
  export function getObserver (value) {
@@ -3,12 +3,13 @@ import { RefKey } from '../helper/const'
3
3
  import {
4
4
  warn,
5
5
  isPlainObject,
6
- hasOwn
6
+ hasOwn,
7
+ extend
7
8
  } from '@mpxjs/utils'
8
9
 
9
10
  export class RefImpl {
10
11
  constructor (options) {
11
- Object.defineProperty(this, 'value', { enumerable: true, ...options })
12
+ Object.defineProperty(this, 'value', extend({ enumerable: true }, options))
12
13
  }
13
14
  }
14
15
 
@@ -83,6 +83,10 @@ export function queueJob (job) {
83
83
  }
84
84
  }
85
85
 
86
+ export function hasPendingJob (job) {
87
+ return queue.length && queue.includes(job, isFlushing && job.allowRecurse ? flushIndex + 1 : flushIndex)
88
+ }
89
+
86
90
  function queueFlush () {
87
91
  if (!isFlushing && !isFlushPending) {
88
92
  isFlushPending = true
@@ -12,7 +12,8 @@ import {
12
12
  isArray,
13
13
  remove,
14
14
  callWithErrorHandling,
15
- hasChanged
15
+ hasChanged,
16
+ extend
16
17
  } from '@mpxjs/utils'
17
18
 
18
19
  export function watchEffect (effect, options) {
@@ -20,11 +21,11 @@ export function watchEffect (effect, options) {
20
21
  }
21
22
 
22
23
  export function watchPostEffect (effect, options) {
23
- return watch(effect, null, { ...options, flush: 'post' })
24
+ return watch(effect, null, extend({}, options, { flush: 'post' }))
24
25
  }
25
26
 
26
27
  export function watchSyncEffect (effect, options) {
27
- return watch(effect, null, { ...options, flush: 'sync' })
28
+ return watch(effect, null, extend({}, options, { flush: 'sync' }))
28
29
  }
29
30
 
30
31
  const warnInvalidSource = (s) => {
@@ -34,7 +35,7 @@ const warnInvalidSource = (s) => {
34
35
  const shouldTrigger = (value, oldValue) => hasChanged(value, oldValue) || isObject(value)
35
36
 
36
37
  const processWatchOptionsCompat = (options) => {
37
- const newOptions = { ...options }
38
+ const newOptions = extend({}, options)
38
39
  if (options.sync) {
39
40
  newOptions.flush = 'sync'
40
41
  }
@@ -37,6 +37,11 @@ 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
+ ]
40
45
  } else {
41
46
  // 此为差异抹平类mixins,原生模式下也需要注入也抹平平台差异
42
47
  bulitInMixins = [
@@ -0,0 +1,40 @@
1
+ import { CREATED, ONSHOW, ONHIDE } from '../../core/innerLifecycle'
2
+
3
+ export default function pageStatusMixin (mixinType) {
4
+ if (mixinType === 'page') {
5
+ return {
6
+ data: {
7
+ mpxPageStatus: 'show'
8
+ },
9
+ onShow () {
10
+ this.mpxPageStatus = 'show'
11
+ this.__mpxProxy.callHook(ONSHOW)
12
+ },
13
+ onHide () {
14
+ this.mpxPageStatus = 'hide'
15
+ this.__mpxProxy.callHook(ONHIDE)
16
+ },
17
+ onBack () {
18
+ return this.onBack && this.onBack()
19
+ }
20
+ }
21
+ }
22
+ // components
23
+ return {
24
+ [CREATED] () {
25
+ const pageInstance = global.__currentPageInstance
26
+ if (!pageInstance) return
27
+ this.$watch(
28
+ () => pageInstance.mpxPageStatus,
29
+ status => {
30
+ if (!status) return
31
+ const pageLifetimes = (this.$rawOptions && this.$rawOptions.pageLifetimes) || {}
32
+ // show & hide
33
+ if (status in pageLifetimes && typeof pageLifetimes[status] === 'function') {
34
+ pageLifetimes[status].call(this)
35
+ }
36
+ }
37
+ )
38
+ }
39
+ }
40
+ }
@@ -0,0 +1,46 @@
1
+ import { setByPath } from '@mpxjs/utils'
2
+
3
+ export default function proxyEventMixin () {
4
+ const methods = {
5
+ triggerEvent (eventName, eventDetail) {
6
+ return this.$emit(eventName, {
7
+ type: eventName,
8
+ detail: eventDetail
9
+ })
10
+ },
11
+ __model (expr, $event, valuePath = ['value'], filterMethod) {
12
+ const innerFilter = {
13
+ trim: val => typeof val === 'string' && val.trim()
14
+ }
15
+ const originValue = valuePath.reduce((acc, cur) => acc[cur], $event.detail)
16
+ const value = filterMethod ? (innerFilter[filterMethod] ? innerFilter[filterMethod](originValue) : typeof this[filterMethod] === 'function' && this[filterMethod]) : originValue
17
+ setByPath(this, expr, value)
18
+ },
19
+ getOpenerEventChannel () {
20
+ const router = global.__mpxRouter
21
+ const eventChannel = router && router.__mpxAction && router.__mpxAction.eventChannel
22
+ return eventChannel
23
+ }
24
+ }
25
+
26
+ return {
27
+ beforeCreate () {
28
+ const modelEvent = this.$attrs.mpxModelEvent
29
+ const modelEventId = this.$attrs.mpxModelEventId
30
+ if (modelEvent && modelEventId) {
31
+ Hummer.notifyCenter.addEventListener(modelEventId, (e) => {
32
+ this.$emit('mpxModel', e)
33
+ })
34
+ }
35
+ },
36
+ beforeDestroy () {
37
+ const modelEvent = this.$attrs.mpxModelEvent
38
+ const modelEventId = this.$attrs.mpxModelEventId
39
+ if (modelEvent && modelEventId) {
40
+ Hummer.notifyCenter.removeEventListener(modelEventId)
41
+ }
42
+ },
43
+
44
+ methods
45
+ }
46
+ }
@@ -1,4 +1,4 @@
1
- import { isObject, isArray, dash2hump, cached } from '@mpxjs/utils'
1
+ import { isObject, isArray, dash2hump, cached, isEmptyObject } from '@mpxjs/utils'
2
2
  import { Dimensions, StyleSheet } from 'react-native'
3
3
 
4
4
  let { width, height } = Dimensions.get('screen')
@@ -26,6 +26,8 @@ const unit = {
26
26
  vh
27
27
  }
28
28
 
29
+ const empty = {}
30
+
29
31
  function formatValue (value) {
30
32
  const matched = unitRegExp.exec(value)
31
33
  if (matched) {
@@ -179,9 +181,9 @@ export default function styleHelperMixin () {
179
181
  } else if (appClassMap[className]) {
180
182
  // todo 全局样式在每个页面和组件中生效,以支持全局原子类,后续支持样式模块复用后可考虑移除
181
183
  Object.assign(result, appClassMap[className])
182
- } else if (this.props[className] && isObject(this.props[className])) {
184
+ } else if (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
  }