@mpxjs/core 2.6.108 → 2.6.114-alpha.1

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 (36) hide show
  1. package/@types/global.d.ts +1 -1
  2. package/@types/index.d.ts +31 -4
  3. package/@types/mpx-store.d.ts +2 -0
  4. package/@types/node.d.ts +0 -2
  5. package/README.md +0 -1
  6. package/package.json +4 -2
  7. package/src/convertor/convertor.js +6 -0
  8. package/src/convertor/getConvertMode.js +1 -0
  9. package/src/convertor/wxToAli.js +5 -1
  10. package/src/convertor/wxToSwan.js +5 -1
  11. package/src/convertor/wxToTenon.js +85 -0
  12. package/src/convertor/wxToWeb.js +6 -1
  13. package/src/core/createStore.js +32 -3
  14. package/src/core/proxy.js +12 -8
  15. package/src/core/transferOptions.js +1 -1
  16. package/src/helper/MpxScroll/index.js +2 -1
  17. package/src/helper/log.js +1 -14
  18. package/src/index.js +25 -1
  19. package/src/platform/builtInMixins/index.js +5 -0
  20. package/src/platform/builtInMixins/pageRouteMixin.js +1 -3
  21. package/src/platform/builtInMixins/pageStatusMixin.tenon.js +40 -0
  22. package/src/platform/builtInMixins/proxyEventMixin.js +2 -0
  23. package/src/platform/builtInMixins/proxyEventMixin.tenon.js +37 -0
  24. package/src/platform/builtInPlugins/hummerStorePlugin.js +1 -0
  25. package/src/platform/builtInPlugins/hummerStorePlugin.tenon.js +3 -0
  26. package/src/platform/createApp.js +8 -1
  27. package/src/platform/patch/ali/lifecycle.js +1 -1
  28. package/src/platform/patch/builtInKeysMap.js +1 -1
  29. package/src/platform/patch/index.js +5 -2
  30. package/src/platform/patch/swan/getDefaultOptions.js +9 -16
  31. package/src/platform/patch/swan/lifecycle.js +2 -1
  32. package/src/platform/patch/tenon/getDefaultOptions.js +58 -0
  33. package/src/platform/patch/tenon/lifecycle.js +48 -0
  34. package/src/platform/patch/web/getDefaultOptions.js +0 -1
  35. package/src/platform/patch/wx/getDefaultOptions.js +4 -2
  36. package/src/vue.tenon.js +13 -0
@@ -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/@types/index.d.ts CHANGED
@@ -44,6 +44,10 @@ type UnionToIntersection<U> = (U extends any
44
44
  ? I
45
45
  : never;
46
46
 
47
+ type RemoveNeverProps<T> = Pick<T, {
48
+ [K in keyof T]: T[K] extends never ? never : K
49
+ }[keyof T]>
50
+
47
51
  type ArrayType<T extends any[]> = T extends Array<infer R> ? R : never;
48
52
 
49
53
  // Mpx types
@@ -288,8 +292,31 @@ type MixinType = 'app' | 'page' | 'component'
288
292
 
289
293
  export function injectMixins (mixins: object | Array<object>, options?: MixinType | MixinType[] | { types?: MixinType | MixinType[], stage?: number }): void
290
294
 
295
+ declare class Watcher {
296
+ constructor (context: any, expr: string | (() => any), handler: WatchHandler | WatchOptWithHandler, options?: WatchOpt)
297
+
298
+ getValue (): any
299
+
300
+ update (): void
301
+
302
+ run (): void
303
+
304
+ destroy (): void
305
+ }
306
+
291
307
  export function watch (expr: string | (() => any), handler: WatchHandler | WatchOptWithHandler, options?: WatchOpt): () => void
292
308
 
309
+ type SupportedPlantforms = 'wx' | 'ali' | 'qq' | 'tt' | 'swan'
310
+
311
+ interface ConvertRule {
312
+ lifecycle?: object
313
+ lifecycleTemplate?: SupportedPlantforms
314
+ lifecycleProxyMap?: object
315
+ pageMode?: 'blend' | ''
316
+ support?: boolean
317
+ convert?: (...args: any[]) => any
318
+ }
319
+
293
320
  interface AnyConstructor {
294
321
  new (...args: any[]): any
295
322
 
@@ -297,10 +324,10 @@ interface AnyConstructor {
297
324
  }
298
325
 
299
326
  interface MpxConfig {
300
- useStrictDiff: boolean
301
- ignoreWarning: boolean | string | RegExp | ((msg: string, location: string, e: Error) => boolean)
327
+ useStrictDiff: Boolean
328
+ ignoreRenderError: Boolean
302
329
  ignoreConflictWhiteList: Array<string>
303
- observeClassInstance: boolean | Array<AnyConstructor>
330
+ observeClassInstance: Boolean | Array<AnyConstructor>
304
331
  hookErrorHandler: (e: Error, target: ComponentIns<{}, {}, {}, {}, []>, hookName: string) => any | null
305
332
  proxyEventHandler: (e: Event) => any | null
306
333
  setDataHandler: (data: object, target: ComponentIns<{}, {}, {}, {}, []>) => any | null
@@ -313,7 +340,7 @@ type SupportedMode = 'wx' | 'ali' | 'qq' | 'swan' | 'tt' | 'web' | 'qa'
313
340
  interface ImplementOptions {
314
341
  modes?: Array<SupportedMode>
315
342
  processor?: () => any
316
- remove?: boolean
343
+ remove?: Boolean
317
344
  }
318
345
 
319
346
  export function toPureObject<T extends object> (obj: T): T
@@ -129,8 +129,10 @@ declare namespace MpxStore {
129
129
 
130
130
  /**
131
131
  * remove compatible code in Mpx.
132
+ *
132
133
  * if you need using createStoreWithThis mix with createStore
133
134
  * you can add a global define file
135
+ *
134
136
  * use Declaration Merging(https://www.typescriptlang.org/docs/handbook/declaration-merging.html) on CompatibleDispatch:
135
137
  * @example
136
138
  * declare module MpxStore {
package/@types/node.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- // @ts-ignore
2
1
  declare let global: Record<string, any> // in web, we use global varible to do some things, here to declare
3
2
 
4
3
  type Dict<T> = {
@@ -7,7 +6,6 @@ type Dict<T> = {
7
6
 
8
7
  type EnvType = Dict<string>
9
8
 
10
- // @ts-ignore
11
9
  declare let process: {
12
10
  env: EnvType
13
11
  }
package/README.md CHANGED
@@ -1,4 +1,3 @@
1
1
  # 小程序框架 [**MPX** 介绍文档](https://didi.github.io/mpx)
2
2
 
3
3
  ## 跨平台代码编写指南
4
-
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mpxjs/core",
3
- "version": "2.6.108",
3
+ "version": "2.6.114-alpha.1",
4
4
  "description": "mpx runtime core",
5
5
  "keywords": [
6
6
  "miniprogram",
@@ -23,6 +23,8 @@
23
23
  "miniprogram-api-typings": "^3.0.2"
24
24
  },
25
25
  "peerDependencies": {
26
+ "@hummer/tenon-store": "^1.4.0",
27
+ "@hummer/tenon-vue": "^1.5.1",
26
28
  "vue": "^2.6.10",
27
29
  "vue-i18n": "^8.15.3"
28
30
  },
@@ -41,5 +43,5 @@
41
43
  "url": "https://github.com/didi/mpx/issues"
42
44
  },
43
45
  "sideEffects": false,
44
- "gitHead": "5efa2dec1597b0b7dd45e46b3ddf23bf46e25177"
46
+ "gitHead": "c343d0ec9b5595b336a567f311eb1bd4d0f4a1e0"
45
47
  }
@@ -1,11 +1,13 @@
1
1
  import * as wxLifecycle from '../platform/patch/wx/lifecycle'
2
2
  import * as aliLifecycle from '../platform/patch/ali/lifecycle'
3
3
  import * as webLifecycle from '../platform/patch/web/lifecycle'
4
+ import * as tenonLifecycle from '../platform/patch/tenon/lifecycle'
4
5
  import * as swanLifecycle from '../platform/patch/swan/lifecycle'
5
6
  import { mergeLifecycle } from './mergeLifecycle'
6
7
  import { error } from '../helper/log'
7
8
  import wxToAliRule from './wxToAli'
8
9
  import wxToWebRule from './wxToWeb'
10
+ import wxToTenonRule from './wxToTenon'
9
11
  import wxToSwanRule from './wxToSwan'
10
12
  import wxToQqRule from './wxToQq'
11
13
  import wxToTtRule from './wxToTt'
@@ -19,6 +21,9 @@ let pageMode
19
21
  if (__mpx_mode__ === 'web') {
20
22
  lifecycleInfo = webLifecycle
21
23
  pageMode = ''
24
+ } else if (__mpx_mode__ === 'tenon') {
25
+ lifecycleInfo = tenonLifecycle
26
+ pageMode = ''
22
27
  } else if (__mpx_mode__ === 'ali') {
23
28
  lifecycleInfo = aliLifecycle
24
29
  pageMode = ''
@@ -50,6 +55,7 @@ const rulesMap = {
50
55
  local: { ...defaultConvertRule },
51
56
  default: defaultConvertRule,
52
57
  wxToWeb: wxToWebRule,
58
+ wxToTenon: wxToTenonRule,
53
59
  wxToAli: wxToAliRule,
54
60
  wxToSwan: wxToSwanRule,
55
61
  wxToQq: { ...defaultConvertRule, ...wxToQqRule },
@@ -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',
@@ -5,6 +5,7 @@ import { mergeToArray } from '../core/mergeOptions'
5
5
  import { error } from '../helper/log'
6
6
  import { implemented } from '../core/implement'
7
7
  import { hasOwn } from '../helper/utils'
8
+ import { CREATED } from '../core/innerLifecycle'
8
9
 
9
10
  const unsupported = ['moved', 'definitionFilter']
10
11
 
@@ -43,7 +44,10 @@ export default {
43
44
  lifecycle2: mergeLifecycle(aliLifecycle.LIFECYCLE),
44
45
  pageMode: 'blend',
45
46
  support: false,
46
- lifecycleProxyMap: wxLifecycle.lifecycleProxyMap,
47
+ // wx输出ali时额外将onLoad代理到CREATED
48
+ lifecycleProxyMap: Object.assign({}, wxLifecycle.lifecycleProxyMap, {
49
+ [CREATED]: ['created', 'attached', 'onLoad']
50
+ }),
47
51
  convert (options) {
48
52
  const props = Object.assign({}, options.properties, options.props)
49
53
  if (props) {
@@ -1,5 +1,6 @@
1
1
  import { error } from '../helper/log'
2
2
  import { implemented } from '../core/implement'
3
+ import { CREATED } from '../core/innerLifecycle'
3
4
  import { mergeLifecycle } from './mergeLifecycle'
4
5
  import * as wxLifecycle from '../platform/patch/wx/lifecycle'
5
6
  import * as swanLifecycle from '../platform/patch/swan/lifecycle'
@@ -33,7 +34,10 @@ export default {
33
34
  lifecycle2: mergeLifecycle(swanLifecycle.LIFECYCLE),
34
35
  pageMode: 'blend',
35
36
  support: true,
36
- lifecycleProxyMap: wxLifecycle.lifecycleProxyMap,
37
+ // wx输出swan时额外将onLoad代理到CREATED
38
+ lifecycleProxyMap: Object.assign({}, wxLifecycle.lifecycleProxyMap, {
39
+ [CREATED]: ['created', 'attached', 'onLoad']
40
+ }),
37
41
  convert (options, type) {
38
42
  if (options.behaviors) {
39
43
  options.behaviors.forEach((behavior, idx) => {
@@ -0,0 +1,85 @@
1
+ import * as wxLifecycle from '../platform/patch/wx/lifecycle'
2
+ import * as tenonLifecycle from '../platform/patch/tenon/lifecycle'
3
+ import { mergeLifecycle } from './mergeLifecycle'
4
+ import { error } from '../helper/log'
5
+ import { isObject, diffAndCloneA, hasOwn } from '../helper/utils'
6
+ import { implemented } from '../core/implement'
7
+ import { CREATED, DESTROYED } from '../core/innerLifecycle'
8
+
9
+ // 暂不支持的wx选项,后期需要各种花式支持
10
+ const unsupported = [
11
+ 'moved',
12
+ 'definitionFilter',
13
+ 'onShareAppMessage',
14
+ 'activated',
15
+ 'deactivated',
16
+ 'pageShow',
17
+ 'pageHide',
18
+ 'onPullDownRefresh',
19
+ 'onReachBottom',
20
+ 'onPageScroll',
21
+ 'onTabItemTap',
22
+ 'onResize',
23
+ 'onUnhandledRejection',
24
+ 'onThemeChange'
25
+ ]
26
+
27
+ function convertErrorDesc (key) {
28
+ error(`Options.${key} is not supported in runtime conversion from wx to tenon.`, global.currentResource)
29
+ }
30
+
31
+ function notSupportTip (options) {
32
+ unsupported.forEach(key => {
33
+ if (options[key]) {
34
+ if (!implemented[key]) {
35
+ process.env.NODE_ENV !== 'production' && convertErrorDesc(key)
36
+ delete options[key]
37
+ } else if (implemented[key].remove) {
38
+ delete options[key]
39
+ }
40
+ }
41
+ })
42
+ }
43
+
44
+ export default {
45
+ lifecycle: mergeLifecycle(wxLifecycle.LIFECYCLE),
46
+ lifecycle2: mergeLifecycle(tenonLifecycle.LIFECYCLE),
47
+ pageMode: 'blend',
48
+ // support传递为true以将methods外层的方法函数合入methods中
49
+ support: true,
50
+ // wx输出tenon时额外将onLoad代理到CREATED
51
+ lifecycleProxyMap: Object.assign({}, wxLifecycle.lifecycleProxyMap, {
52
+ [CREATED]: ['created', 'attached', 'onLoad'],
53
+ [DESTROYED]: ['destroyed', 'detached', 'onUnload', 'unmounted']
54
+ }),
55
+ convert (options) {
56
+ const props = Object.assign({}, options.properties, options.props)
57
+ if (props) {
58
+ Object.keys(props).forEach(key => {
59
+ const prop = props[key]
60
+ if (prop) {
61
+ if (hasOwn(prop, 'type')) {
62
+ const newProp = {}
63
+ if (hasOwn(prop, 'optionalTypes')) {
64
+ newProp.type = [prop.type, ...prop.optionalTypes]
65
+ } else {
66
+ newProp.type = prop.type
67
+ }
68
+ if (hasOwn(prop, 'value')) {
69
+ // vue中对于引用类型数据需要使用函数返回
70
+ newProp.default = isObject(prop.value) ? function propFn () {
71
+ return diffAndCloneA(prop.value).clone
72
+ } : prop.value
73
+ }
74
+ props[key] = newProp
75
+ } else {
76
+ props[key] = prop
77
+ }
78
+ }
79
+ })
80
+ options.props = props
81
+ delete options.properties
82
+ }
83
+ notSupportTip(options)
84
+ }
85
+ }
@@ -4,6 +4,7 @@ import { mergeLifecycle } from './mergeLifecycle'
4
4
  import { error } from '../helper/log'
5
5
  import { isObject, diffAndCloneA, hasOwn } from '../helper/utils'
6
6
  import { implemented } from '../core/implement'
7
+ import { CREATED } from '../core/innerLifecycle'
7
8
 
8
9
  // 暂不支持的wx选项,后期需要各种花式支持
9
10
  const unsupported = ['moved', 'definitionFilter', 'onShareAppMessage', 'pageShow', 'pageHide']
@@ -29,8 +30,12 @@ export default {
29
30
  lifecycle: mergeLifecycle(wxLifecycle.LIFECYCLE),
30
31
  lifecycle2: mergeLifecycle(webLifecycle.LIFECYCLE),
31
32
  pageMode: 'blend',
33
+ // support传递为true以将methods外层的方法函数合入methods中
32
34
  support: true,
33
- lifecycleProxyMap: wxLifecycle.lifecycleProxyMap,
35
+ // wx输出web时额外将onLoad代理到CREATED
36
+ lifecycleProxyMap: Object.assign({}, wxLifecycle.lifecycleProxyMap, {
37
+ [CREATED]: ['created', 'attached', 'onLoad']
38
+ }),
34
39
  convert (options) {
35
40
  const props = Object.assign({}, options.properties, options.props)
36
41
  if (props) {
@@ -4,6 +4,8 @@ import { initComputed } from '../observer/computed'
4
4
 
5
5
  import Vue from '../vue'
6
6
 
7
+ import createHummerPlugin from '../platform/builtInPlugins/hummerStorePlugin'
8
+
7
9
  import {
8
10
  proxy,
9
11
  getByPath
@@ -124,6 +126,12 @@ class Store {
124
126
  this.state = this.registerModule(options).state
125
127
  this.resetStoreVM()
126
128
  Object.assign(this, mapStore(this))
129
+ if (__mpx_mode__ === 'tenon') {
130
+ plugins.push(createHummerPlugin({
131
+ /* eslint-disable camelcase */
132
+ store_key: `MPX_STORE${options.__store_id}`
133
+ }))
134
+ }
127
135
  plugins.forEach(plugin => plugin(this))
128
136
  }
129
137
 
@@ -152,9 +160,9 @@ class Store {
152
160
 
153
161
  registerModule (module) {
154
162
  const state = module.state || {}
155
- const reactiveModule = {
156
- state
157
- }
163
+ const reactiveModule = __mpx_mode__ === 'tenon'
164
+ ? Vue.reactive({ state })
165
+ : { state }
158
166
  if (module.getters) {
159
167
  reactiveModule.getters = transformGetters(module.getters, reactiveModule, this)
160
168
  }
@@ -194,6 +202,16 @@ class Store {
194
202
  const computedKeys = Object.keys(this.__wrappedGetters)
195
203
  proxy(this.getters, this._vm, computedKeys)
196
204
  proxy(this.getters, this.__depsGetters)
205
+ } else if (__mpx_mode__ === 'tenon') {
206
+ const computedObj = {}
207
+ Object.keys(this.__wrappedGetters).forEach(k => {
208
+ const getter = this.__wrappedGetters[k]
209
+ computedObj[k] = () => getter(this.state)
210
+ Object.defineProperty(this.getters, k, {
211
+ get: () => computedObj[k](),
212
+ enumerable: true // for local getters
213
+ })
214
+ })
197
215
  } else {
198
216
  this._vm = {}
199
217
  observe(this.state, true)
@@ -201,6 +219,17 @@ class Store {
201
219
  proxy(this.getters, this.__depsGetters)
202
220
  }
203
221
  }
222
+ /**
223
+ * 替换state,tenon环境中使用
224
+ */
225
+ replaceState (state) {
226
+ // todo 某些key可能无法删除
227
+ Object.assign(this.state, state)
228
+ // this.resetStoreVM()
229
+ }
230
+ _withCommit (fn) {
231
+ fn()
232
+ }
204
233
  }
205
234
 
206
235
  function genericSubscribe (fn, subs, options) {
package/src/core/proxy.js CHANGED
@@ -45,7 +45,7 @@ export default class MPXProxy {
45
45
  this.state = 'initial'
46
46
  this.lockTask = asyncLock()
47
47
  this.ignoreProxyMap = makeMap(EXPORT_MPX.config.ignoreProxyWhiteList)
48
- if (__mpx_mode__ !== 'web') {
48
+ if (__mpx_mode__ !== 'web' && __mpx_mode__ !== 'tenon') {
49
49
  this._watchers = []
50
50
  this._watcher = null
51
51
  this.localKeysMap = {} // 非props key
@@ -60,12 +60,12 @@ export default class MPXProxy {
60
60
  created (params) {
61
61
  this.initApi()
62
62
  this.callUserHook(BEFORECREATE)
63
- if (__mpx_mode__ !== 'web') {
63
+ if (__mpx_mode__ !== 'web' && __mpx_mode__ !== 'tenon') {
64
64
  this.initState(this.options)
65
65
  }
66
66
  this.state = CREATED
67
67
  this.callUserHook(CREATED, params)
68
- if (__mpx_mode__ !== 'web') {
68
+ if (__mpx_mode__ !== 'web' && __mpx_mode__ !== 'tenon') {
69
69
  // 强制走小程序原生渲染逻辑
70
70
  this.options.__nativeRender__ ? this.doRender() : this.initRender()
71
71
  }
@@ -111,7 +111,7 @@ export default class MPXProxy {
111
111
 
112
112
  destroyed () {
113
113
  this.state = DESTROYED
114
- if (__mpx_mode__ !== 'web') {
114
+ if (__mpx_mode__ !== 'web' && __mpx_mode__ !== 'tenon') {
115
115
  this.clearWatchers()
116
116
  }
117
117
  this.callUserHook(DESTROYED)
@@ -136,7 +136,7 @@ export default class MPXProxy {
136
136
  error(`The key [${key}] of page options exist in the page instance already, please check your page options!`, this.options.mpxFileResource)
137
137
  })
138
138
  }
139
- if (__mpx_mode__ !== 'web') {
139
+ if (__mpx_mode__ !== 'web' && __mpx_mode__ !== 'tenon') {
140
140
  // 挂载$watch
141
141
  this.target.$watch = (...rest) => this.watch(...rest)
142
142
  // 强制执行render
@@ -241,7 +241,9 @@ export default class MPXProxy {
241
241
  if (typeof EXPORT_MPX.config.hookErrorHandler === 'function') {
242
242
  EXPORT_MPX.config.hookErrorHandler(e, this.target, hookName)
243
243
  } else {
244
- error(`User hook [${hookName}] exec error!`, this.options.mpxFileResource, e)
244
+ setTimeout(() => {
245
+ throw e
246
+ })
245
247
  }
246
248
  }
247
249
  }
@@ -413,7 +415,9 @@ export default class MPXProxy {
413
415
  try {
414
416
  return this.target.__injectedRender()
415
417
  } catch (e) {
416
- warn(`Failed to execute render function, degrade to full-set-data mode.`, this.options.mpxFileResource, e)
418
+ if (!EXPORT_MPX.config.ignoreRenderError) {
419
+ warn(`Failed to execute render function, degrade to full-set-data mode.`, this.options.mpxFileResource, e)
420
+ }
417
421
  this.render()
418
422
  }
419
423
  }, noop)
@@ -442,7 +446,7 @@ export default class MPXProxy {
442
446
  this.forceUpdateData = data
443
447
  Object.keys(this.forceUpdateData).forEach(key => {
444
448
  if (!this.options.__nativeRender__ && !this.localKeysMap[getFirstKey(key)]) {
445
- warn(`ForceUpdate data includes a props/computed key [${key}], which may yield a unexpected result.`, this.options.mpxFileResource)
449
+ warn(`ForceUpdate data includes a props/computed key [${key}], which may yield a unexpected result!`, this.options.mpxFileResource)
446
450
  }
447
451
  setByPath(this.data, key, this.forceUpdateData[key])
448
452
  })
@@ -32,7 +32,7 @@ export default function transferOptions (options, type) {
32
32
  // 头条和百度小程序由于props传递为异步操作,通过props向子组件传递computed数据时,子组件无法在初始时(created/attached)获取到computed数据,如需进一步处理数据建议通过watch获取
33
33
  currentInject.propKeys.forEach(key => {
34
34
  if (findItem(computedKeys, key)) {
35
- warn(`由于平台机制原因,子组件无法在初始时(created/attached)获取到通过props传递的计算属性[${key}],该问题一般不影响渲染,如需进一步处理数据建议通过watch获取。`, global.currentResource)
35
+ warn(`The child component can't achieve the value of computed prop [${key}] when attached, which is governed by the order of tt miniprogram's lifecycles.`, global.currentResource)
36
36
  }
37
37
  })
38
38
  }
@@ -1,3 +1,4 @@
1
+ import { error } from '../../helper/log'
1
2
  import { getOffsetTop, getElement, getScrollTop, preventDefault } from './dom'
2
3
  import EventEmitter from './EventEmitter'
3
4
  import EventRegister from './EventRegister'
@@ -210,7 +211,7 @@ export default class MpxScroll {
210
211
  } else if (isDef(selector)) {
211
212
  _scrollTop = getOffsetTop(getElement(selector))
212
213
  } else {
213
- return console.error('[pageScrollTo error]: scrollTop and selector are not defined')
214
+ return error('[pageScrollTo error]: scrollTop and selector are not defined')
214
215
  }
215
216
 
216
217
  if (duration === 0) {
package/src/helper/log.js CHANGED
@@ -1,18 +1,5 @@
1
- import EXPORT_MPX from '../index'
2
-
3
1
  export function warn (msg, location, e) {
4
- const condition = EXPORT_MPX.config.ignoreWarning
5
- let ignore = false
6
- if (typeof condition === 'boolean') {
7
- ignore = condition
8
- } else if (typeof condition === 'string') {
9
- ignore = msg.indexOf(condition) !== -1
10
- } else if (typeof condition === 'function') {
11
- ignore = condition(msg, location, e)
12
- } else if (condition instanceof RegExp) {
13
- ignore = condition.test(msg)
14
- }
15
- if (!ignore) return log('warn', msg, location, e)
2
+ return log('warn', msg, location, e)
16
3
  }
17
4
 
18
5
  export function error (msg, location, e) {
package/src/index.js CHANGED
@@ -133,6 +133,30 @@ if (__mpx_mode__ === 'web') {
133
133
  InstanceAPIs = {
134
134
  $remove: remove
135
135
  }
136
+ } else if (__mpx_mode__ === 'tenon') {
137
+ const set = (target, key, value) => {
138
+ return Reflect.set(target, key, value)
139
+ }
140
+ const del = (target, key) => {
141
+ return Reflect.deleteProperty(target, key)
142
+ }
143
+ APIs = {
144
+ createApp,
145
+ createPage,
146
+ createComponent,
147
+ createStore,
148
+ createStoreWithThis,
149
+ mixin: injectMixins,
150
+ injectMixins,
151
+ toPureObject: Vue.toRaw,
152
+ observable: Vue.reactive,
153
+ watch: Vue.watch,
154
+ use,
155
+ set,
156
+ delete: del,
157
+ getMixin,
158
+ implement
159
+ }
136
160
  } else {
137
161
  observable = function (obj) {
138
162
  observe(obj)
@@ -199,7 +223,7 @@ const EXPORT_MPX = factory()
199
223
 
200
224
  EXPORT_MPX.config = {
201
225
  useStrictDiff: false,
202
- ignoreWarning: false,
226
+ ignoreRenderError: false,
203
227
  ignoreProxyWhiteList: ['id', 'dataset', 'data'],
204
228
  observeClassInstance: false,
205
229
  hookErrorHandler: null,
@@ -26,6 +26,11 @@ export default function getBuiltInMixins (options, type) {
26
26
  // 由于relation可能是通过mixin注入的,不能通过当前的用户options中是否存在relations来简单判断是否注入该项mixin
27
27
  relationsMixin(type)
28
28
  ]
29
+ } else if (__mpx_mode__ === 'tenon') {
30
+ bulitInMixins = [
31
+ proxyEventMixin(),
32
+ pageStatusMixin(type)
33
+ ]
29
34
  } else {
30
35
  // 此为差异抹平类mixins,原生模式下也需要注入也抹平平台差异
31
36
  bulitInMixins = [
@@ -3,9 +3,7 @@ export default function pageRouteMixin (mixinType) {
3
3
  if (mixinType === 'page') {
4
4
  return {
5
5
  beforeCreate () {
6
- if (this.$options.__mpxPageRoute) {
7
- this.route = this.$options.__mpxPageRoute.slice(1)
8
- }
6
+ this.route = this.$options.__mpxPageRoute || ''
9
7
  }
10
8
  }
11
9
  }
@@ -0,0 +1,40 @@
1
+ import { CREATED } 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.onShow && this.onShow()
12
+ },
13
+ onHide () {
14
+ this.mpxPageStatus = 'hide'
15
+ this.onHide && this.onHide()
16
+ },
17
+ onBack () {
18
+ this.onBack && this.onBack()
19
+ }
20
+ }
21
+ }
22
+ // components
23
+ return {
24
+ [CREATED] () {
25
+ let 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
+ }
@@ -20,6 +20,8 @@ export default function proxyEventMixin () {
20
20
  if (type === 'begin' || type === 'end') {
21
21
  // 地图的 regionchange 事件会派发 e.type 为 begin 和 end 的事件
22
22
  fallbackType = 'regionchange'
23
+ } else if (__mpx_mode__ === 'ali') {
24
+ fallbackType = type.replace(/^./, i => i.toLowerCase())
23
25
  }
24
26
  const target = $event.currentTarget || $event.target
25
27
  if (!target) {
@@ -0,0 +1,37 @@
1
+ import { setByPath } from '../../helper/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
+ if (modelEvent) {
30
+ this.$on(modelEvent, (e) => {
31
+ this.$emit('mpxModel', e)
32
+ })
33
+ }
34
+ },
35
+ methods
36
+ }
37
+ }
@@ -0,0 +1 @@
1
+ export default () => () => {} // mock plugin in other mode
@@ -0,0 +1,3 @@
1
+ import { createHummerPlugin } from '@hummer/tenon-store'
2
+
3
+ export default createHummerPlugin
@@ -61,6 +61,13 @@ export default function createApp (option, config = {}) {
61
61
  }
62
62
  }
63
63
  })
64
+ } else if (__mpx_mode__ === 'tenon') {
65
+ // todo add tenon mixins
66
+ builtInMixins.push({
67
+ onLaunch () {
68
+ // console.log('tenon mixins')
69
+ }
70
+ })
64
71
  } else {
65
72
  builtInMixins.push({
66
73
  onLaunch () {
@@ -72,7 +79,7 @@ export default function createApp (option, config = {}) {
72
79
  rawOptions.mixins = builtInMixins
73
80
  const defaultOptions = filterOptions(spreadProp(mergeOptions(rawOptions, 'app', false), 'methods'), appData)
74
81
 
75
- if (__mpx_mode__ === 'web') {
82
+ if (__mpx_mode__ === 'web' || __mpx_mode__ === 'tenon') {
76
83
  global.currentOption = defaultOptions
77
84
  global.getApp = function () {
78
85
  return appData
@@ -39,7 +39,7 @@ const COMPONENT_HOOKS = [
39
39
 
40
40
  export const lifecycleProxyMap = {
41
41
  [BEFORECREATE]: ['beforeCreate'],
42
- [CREATED]: ['onInit'],
42
+ [CREATED]: ['onInit', 'onLoad'],
43
43
  [UPDATED]: ['didUpdate', 'updated'],
44
44
  [BEFOREMOUNT]: ['beforeMount'],
45
45
  [MOUNTED]: ['didMount', 'onReady'],
@@ -3,7 +3,7 @@ import { makeMap } from '../../helper/utils'
3
3
 
4
4
  let bulitInKeys
5
5
 
6
- if (__mpx_mode__ === 'web') {
6
+ if (__mpx_mode__ === 'web' || __mpx_mode__ === 'tenon') {
7
7
  bulitInKeys = [
8
8
  'proto',
9
9
  'mixins',
@@ -4,6 +4,7 @@ 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 { getDefaultOptions as getTenonDefaultOptions } from './tenon/getDefaultOptions'
7
8
  import { error } from '../../helper/log'
8
9
 
9
10
  export default function createFactory (type) {
@@ -11,7 +12,7 @@ export default function createFactory (type) {
11
12
  options.__nativeRender__ = !!isNative
12
13
  options.__type__ = type
13
14
  let ctor
14
- if (__mpx_mode__ !== 'web') {
15
+ if (__mpx_mode__ !== 'web' && __mpx_mode__ !== 'tenon') {
15
16
  if (customCtor) {
16
17
  ctor = customCtor
17
18
  customCtorType = customCtorType || type
@@ -41,6 +42,8 @@ export default function createFactory (type) {
41
42
  let getDefaultOptions
42
43
  if (__mpx_mode__ === 'web') {
43
44
  getDefaultOptions = getWebDefaultOptions
45
+ } else if (__mpx_mode__ === 'tenon') {
46
+ getDefaultOptions = getTenonDefaultOptions
44
47
  } else if (__mpx_mode__ === 'ali') {
45
48
  getDefaultOptions = getAliDefaultOptions
46
49
  } else if (__mpx_mode__ === 'swan') {
@@ -54,7 +57,7 @@ export default function createFactory (type) {
54
57
  // 将合并后的用户定义的rawOptions传入获取当前应该注入的内建mixins
55
58
  rawOptions.mixins = getBuiltInMixins(rawOptions, type)
56
59
  const defaultOptions = getDefaultOptions(type, { rawOptions, currentInject })
57
- if (__mpx_mode__ === 'web') {
60
+ if (__mpx_mode__ === 'web' || __mpx_mode__ === 'tenon') {
58
61
  global.currentOption = defaultOptions
59
62
  } else if (ctor) {
60
63
  return ctor(defaultOptions)
@@ -2,13 +2,17 @@ import mergeOptions from '../../../core/mergeOptions'
2
2
  import { initProxy, filterOptions } from '../wx/getDefaultOptions'
3
3
 
4
4
  export function getDefaultOptions (type, { rawOptions = {}, currentInject }) {
5
- let hookNames = ['attached', 'ready', 'detached']
5
+ const hookNames = ['attached', 'ready', 'detached']
6
+ // 构造页面时统一使用onInit进行初始化
7
+ if (type === 'page') {
8
+ hookNames[0] = 'onInit'
9
+ }
6
10
  // 当用户传入page作为构造器构造页面时,修改所有关键hooks
7
11
  if (rawOptions.__pageCtor__) {
8
- hookNames = ['onLoad', 'onReady', 'onUnload']
12
+ hookNames[1] = 'onReady'
13
+ hookNames[2] = 'onUnload'
9
14
  }
10
-
11
- const rootMixin = {
15
+ const rootMixins = [{
12
16
  [hookNames[0]] (...params) {
13
17
  if (!this.__mpxProxy) {
14
18
  initProxy(this, rawOptions, currentInject, params)
@@ -20,18 +24,7 @@ export function getDefaultOptions (type, { rawOptions = {}, currentInject }) {
20
24
  [hookNames[2]] () {
21
25
  this.__mpxProxy && this.__mpxProxy.destroyed()
22
26
  }
23
- }
24
-
25
- // 如构造页面,优先使用onInit进行初始化
26
- if (type === 'page') {
27
- rootMixin.onInit = function (...params) {
28
- if (!this.__mpxProxy) {
29
- initProxy(this, rawOptions, currentInject, params)
30
- }
31
- }
32
- }
33
-
34
- const rootMixins = [rootMixin]
27
+ }]
35
28
  rawOptions.mixins = rawOptions.mixins ? rootMixins.concat(rawOptions.mixins) : rootMixins
36
29
  rawOptions = mergeOptions(rawOptions, type, false)
37
30
  return filterOptions(rawOptions)
@@ -40,7 +40,8 @@ const COMPONENT_HOOKS = [
40
40
 
41
41
  export const lifecycleProxyMap = {
42
42
  [BEFORECREATE]: ['beforeCreate'],
43
- [CREATED]: ['onInit', 'created', 'attached'],
43
+ // 为提升性能统一把onInit和onLoad都代理到CREATED中,由onInit触发
44
+ [CREATED]: ['onInit', 'created', 'attached', 'onLoad'],
44
45
  [UPDATED]: ['updated'],
45
46
  [BEFOREMOUNT]: ['beforeMount'],
46
47
  [MOUNTED]: ['ready', 'onReady'],
@@ -0,0 +1,58 @@
1
+ import builtInKeysMap from '../builtInKeysMap'
2
+ import mergeOptions from '../../../core/mergeOptions'
3
+ import MPXProxy from '../../../core/proxy'
4
+ import { diffAndCloneA } from '../../../helper/utils'
5
+
6
+ function filterOptions (options) {
7
+ const newOptions = {}
8
+ Object.keys(options).forEach(key => {
9
+ if (builtInKeysMap[key]) {
10
+ return
11
+ }
12
+ // Tenon 使用的Vue3 语法中 data 配置需要为一个函数
13
+ if (key === 'data' || key === 'dataFn') {
14
+ newOptions.data = function mergeFn () {
15
+ return Object.assign(
16
+ diffAndCloneA(options.data || {}).clone,
17
+ options.dataFn && options.dataFn.call(this)
18
+ )
19
+ }
20
+ } else {
21
+ newOptions[key] = options[key]
22
+ }
23
+ })
24
+ return newOptions
25
+ }
26
+
27
+ function initProxy (context, rawOptions) {
28
+ // 缓存options
29
+ context.$rawOptions = rawOptions
30
+ // 创建proxy对象
31
+ const mpxProxy = new MPXProxy(rawOptions, context)
32
+ context.__mpxProxy = mpxProxy
33
+ context.__mpxProxy.created(Hummer.pageInfo && Hummer.pageInfo.params && [Hummer.pageInfo.params])
34
+ }
35
+
36
+ export function getDefaultOptions (type, { rawOptions = {}, currentInject }) {
37
+ const hookNames = type === 'page' ? ['onLoad', 'onReady', 'onUnload'] : ['created', 'mounted', 'unmounted']
38
+ const rootMixins = [{
39
+ [hookNames[0]] (...params) {
40
+ if (!this.__mpxProxy) {
41
+ initProxy(this, rawOptions, currentInject, params)
42
+ }
43
+ },
44
+ [hookNames[1]] () {
45
+ this.__mpxProxy && this.__mpxProxy.mounted(Hummer.pageInfo && Hummer.pageInfo.params && [Hummer.pageInfo.params])
46
+ },
47
+ updated () {
48
+ this.__mpxProxy && this.__mpxProxy.updated()
49
+ },
50
+ [hookNames[2]] () {
51
+ this.__mpxProxy && this.__mpxProxy.destroyed()
52
+ }
53
+ }]
54
+ // 为了在builtMixin中可以使用某些rootMixin实现的特性(如数据响应等),此处builtInMixin在rootMixin之后执行,但是当builtInMixin使用存在对应内建生命周期的目标平台声明周期写法时,可能会出现用户生命周期比builtInMixin中的生命周期先执行的情况,为了避免这种情况发生,builtInMixin应该尽可能使用内建生命周期来编写
55
+ rawOptions.mixins = rawOptions.mixins ? rootMixins.concat(rawOptions.mixins) : rootMixins
56
+ rawOptions = mergeOptions(rawOptions, type, false)
57
+ return filterOptions(rawOptions)
58
+ }
@@ -0,0 +1,48 @@
1
+ const COMPONENT_HOOKS = [
2
+ 'beforeCreate',
3
+ 'created',
4
+ 'beforeMount',
5
+ 'mounted',
6
+ 'beforeUpdate',
7
+ 'updated',
8
+ // 'activated',
9
+ // 'deactivated',
10
+ 'beforeDestroy',
11
+ 'destroyed',
12
+ 'errorCaptured',
13
+ 'beforeUnmount',
14
+ 'unmounted'
15
+ // 'onPageNotFound'
16
+ ]
17
+
18
+ const PAGE_HOOKS = [
19
+ ...COMPONENT_HOOKS,
20
+ 'onLoad',
21
+ 'onReady',
22
+ 'onShow',
23
+ 'onHide',
24
+ 'onUnload'
25
+ // 'onBack',
26
+ // 'onPullDownRefresh',
27
+ // 'onReachBottom',
28
+ // 'onPageScroll',
29
+ // 'onTabItemTap',
30
+ // 'onResize'
31
+ ]
32
+
33
+ const APP_HOOKS = [
34
+ ...COMPONENT_HOOKS,
35
+ 'onLaunch',
36
+ 'onShow',
37
+ 'onHide',
38
+ 'onError'
39
+ // 'onPageNotFound',
40
+ // 'onUnhandledRejection',
41
+ // 'onThemeChange'
42
+ ]
43
+
44
+ export const LIFECYCLE = {
45
+ APP_HOOKS,
46
+ PAGE_HOOKS,
47
+ COMPONENT_HOOKS
48
+ }
@@ -38,7 +38,6 @@ export function getDefaultOptions (type, { rawOptions = {} }) {
38
38
  if (!this.__mpxProxy) {
39
39
  const query = (global.__mpxRouter && global.__mpxRouter.currentRoute && global.__mpxRouter.currentRoute.query) || {}
40
40
  initProxy(this, rawOptions, [query])
41
- this.onLoad && this.onLoad(query)
42
41
  }
43
42
  },
44
43
  mounted () {
@@ -128,10 +128,12 @@ export function initProxy (context, rawOptions, currentInject, params) {
128
128
  }
129
129
 
130
130
  export function getDefaultOptions (type, { rawOptions = {}, currentInject }) {
131
- let hookNames = ['attached', 'ready', 'detached']
131
+ const hookNames = ['attached', 'ready', 'detached']
132
132
  // 当用户传入page作为构造器构造页面时,修改所有关键hooks
133
133
  if (rawOptions.__pageCtor__) {
134
- hookNames = ['onLoad', 'onReady', 'onUnload']
134
+ hookNames[0] = 'onLoad'
135
+ hookNames[1] = 'onReady'
136
+ hookNames[2] = 'onUnload'
135
137
  }
136
138
  const rootMixins = [{
137
139
  [hookNames[0]] (...params) {
@@ -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
+ }