@mpxjs/core 2.9.0-beta.3 → 2.9.0-beta.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/@types/index.d.ts CHANGED
@@ -46,7 +46,7 @@ type FullPropType<T> = {
46
46
  }
47
47
 
48
48
  interface Properties {
49
- [key: string]: WechatMiniprogram.Component.AllProperty | PropType<any> | FullPropType<any>
49
+ [key: string]: WechatMiniprogram.Component.AllProperty
50
50
  }
51
51
 
52
52
  interface Methods {
@@ -82,12 +82,12 @@ type PropValueType<Def> = Def extends {
82
82
  }
83
83
  ? T
84
84
  : Def extends (...args: any[]) => infer T
85
- ? T
86
- : Def extends FullPropType<infer T>
87
- ? T
88
- : Def extends PropType<infer T>
89
- ? T
90
- : any;
85
+ ? T
86
+ : Def extends FullPropType<infer T>
87
+ ? T
88
+ : Def extends PropType<infer T>
89
+ ? T
90
+ : any;
91
91
 
92
92
  type GetPropsType<T> = {
93
93
  readonly [K in keyof T]: PropValueType<T[K]>
@@ -240,7 +240,10 @@ export function createApp<T extends WechatMiniprogram.IAnyObject> (opt: WechatMi
240
240
 
241
241
  type MixinType = 'app' | 'page' | 'component'
242
242
 
243
- export function injectMixins (mixins: object | Array<object>, options?: MixinType | MixinType[] | { types?: MixinType | MixinType[], stage?: number }): Mpx
243
+ export function injectMixins (mixins: object | Array<object>, options?: MixinType | MixinType[] | {
244
+ types?: MixinType | MixinType[],
245
+ stage?: number
246
+ }): Mpx
244
247
 
245
248
  // export function watch (expr: string | (() => any), handler: WatchHandler | WatchOptWithHandler, options?: WatchOpt): () => void
246
249
 
@@ -339,7 +342,7 @@ export interface Ref<T = any> {
339
342
  * We need this to be in public d.ts but don't want it to show up in IDE
340
343
  * autocomplete, so we use a private Symbol instead.
341
344
  */
342
- [RefSymbol]: true
345
+ [RefSymbol]: true
343
346
  }
344
347
 
345
348
  type CollectionTypes = IterableCollections | WeakCollections
@@ -448,7 +451,11 @@ export interface WatchOptions extends WatchEffectOptions {
448
451
 
449
452
  interface EffectScope {
450
453
  run<T> (fn: () => T): T | undefined // 如果作用域不活跃就为 undefined
451
- stop (): void
454
+ stop (fromParent?: boolean): void
455
+
456
+ pause (): void
457
+
458
+ resume (ignoreDirty?: boolean): void
452
459
  }
453
460
 
454
461
 
@@ -614,7 +621,7 @@ export function onTabItemTap (callback: WechatMiniprogram.Page.ILifetime['onTabI
614
621
  export function onSaveExitState (callback: () => void): void
615
622
 
616
623
  // get instance
617
- export function getCurrentInstance<T extends ComponentIns<{}, {}, {}>> (): T
624
+ export function getCurrentInstance<T extends ComponentIns<{}, {}, {}>> (): { proxy: T, [x: string]: any }
618
625
 
619
626
  // I18n
620
627
  export function useI18n<Options extends {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mpxjs/core",
3
- "version": "2.9.0-beta.3",
3
+ "version": "2.9.0-beta.5",
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.0-beta.3",
22
+ "@mpxjs/utils": "^2.9.0-beta.4",
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": "521f0cec1231962f9c071c8b70499772a0a81fda"
50
+ "gitHead": "874e5d0915a28d527091090ff64ad2d182e43525"
51
51
  }
@@ -314,17 +314,19 @@ export function mergeToArray (parent, child, key) {
314
314
  function composeHooks (target, includes) {
315
315
  Object.keys(target).forEach(key => {
316
316
  if (!includes || includes[key]) {
317
- const hooksArr = target[key]
318
- hooksArr && (target[key] = function (...args) {
319
- let result
320
- for (let i = 0; i < hooksArr.length; i++) {
321
- if (typeof hooksArr[i] === 'function') {
322
- const data = hooksArr[i].apply(this, args)
323
- data !== undefined && (result = data)
317
+ const hooks = target[key]
318
+ if (Array.isArray(hooks)) {
319
+ target[key] = function (...args) {
320
+ let result
321
+ for (let i = 0; i < hooks.length; i++) {
322
+ if (typeof hooks[i] === 'function') {
323
+ const data = hooks[i].apply(this, args)
324
+ data !== undefined && (result = data)
325
+ }
324
326
  }
327
+ return result
325
328
  }
326
- return result
327
- })
329
+ }
328
330
  }
329
331
  })
330
332
  }
package/src/core/proxy.js CHANGED
@@ -312,7 +312,16 @@ export default class MpxProxy {
312
312
  watch (source, cb, options) {
313
313
  const target = this.target
314
314
  const getter = isString(source)
315
- ? () => getByPath(target, source)
315
+ ? () => {
316
+ // for watch multi path string like 'a.b,c,d'
317
+ if (source.indexOf(',') > -1) {
318
+ return source.split(',').map(path => {
319
+ return getByPath(target, path.trim())
320
+ })
321
+ } else {
322
+ return getByPath(target, source)
323
+ }
324
+ }
316
325
  : source.bind(target)
317
326
 
318
327
  if (isObject(cb)) {
@@ -530,6 +539,10 @@ export default class MpxProxy {
530
539
  initRender () {
531
540
  if (this.options.__nativeRender__) return this.doRender()
532
541
 
542
+ const _i = this.target._i.bind(this.target)
543
+ const _c = this.target._c.bind(this.target)
544
+ const _r = this.target._r.bind(this.target)
545
+ const _sc = this.target._sc.bind(this.target)
533
546
  const effect = this.effect = new ReactiveEffect(() => {
534
547
  // pre render for props update
535
548
  if (this.propsUpdatedFlag) {
@@ -538,7 +551,7 @@ export default class MpxProxy {
538
551
 
539
552
  if (this.target.__injectedRender) {
540
553
  try {
541
- return this.target.__injectedRender()
554
+ return this.target.__injectedRender(_i, _c, _r, _sc)
542
555
  } catch (e) {
543
556
  warn('Failed to execute render function, degrade to full-set-data mode.', this.options.mpxFileResource, e)
544
557
  this.render()
@@ -119,7 +119,9 @@ export class ReactiveEffect {
119
119
  }
120
120
 
121
121
  pause () {
122
- this.pausedState = PausedState.paused
122
+ if (this.pausedState !== PausedState.dirty) {
123
+ this.pausedState = PausedState.paused
124
+ }
123
125
  }
124
126
 
125
127
  resume (ignoreDirty = false) {
@@ -1,4 +1,4 @@
1
- import { setByPath, error, hasOwn } from '@mpxjs/utils'
1
+ import { setByPath, error, hasOwn, dash2hump } from '@mpxjs/utils'
2
2
  import Mpx from '../../index'
3
3
 
4
4
  const datasetReg = /^data-(.+)$/
@@ -36,6 +36,8 @@ export default function proxyEventMixin () {
36
36
  if (type === 'begin' || type === 'end') {
37
37
  // 地图的 regionchange 事件会派发 e.type 为 begin 和 end 的事件
38
38
  fallbackType = 'regionchange'
39
+ } else if (/-([a-z])/.test(type)) {
40
+ fallbackType = dash2hump(type)
39
41
  } else if (__mpx_mode__ === 'ali') {
40
42
  fallbackType = type.replace(/^./, i => i.toLowerCase())
41
43
  }
@@ -89,34 +91,22 @@ export default function proxyEventMixin () {
89
91
  }
90
92
  if (__mpx_mode__ === 'ali') {
91
93
  Object.assign(methods, {
92
- triggerEvent (eventName, eventDetail, e) {
94
+ triggerEvent (eventName, eventDetail) {
93
95
  const handlerName = eventName.replace(/^./, matched => matched.toUpperCase()).replace(/-([a-z])/g, (match, p1) => p1.toUpperCase())
94
96
  const handler = this.props && (this.props['on' + handlerName] || this.props['catch' + handlerName])
95
97
  if (handler && typeof handler === 'function') {
96
- let eventObj = {}
97
- if (e) {
98
- e.detail = Object.assign(e.detail, eventDetail)
99
- eventObj = e
100
- } else {
101
- const dataset = collectDataset(this.props)
102
- const id = this.props.id || ''
103
- const timeStamp = +new Date()
104
- eventObj = {
105
- type: eventName,
106
- timeStamp,
107
- target: { id, dataset, targetDataset: dataset },
108
- currentTarget: { id, dataset },
109
- detail: eventDetail
110
- }
98
+ const dataset = collectDataset(this.props)
99
+ const id = this.props.id || ''
100
+ const timeStamp = +new Date()
101
+ const eventObj = {
102
+ type: eventName,
103
+ timeStamp,
104
+ target: { id, dataset, targetDataset: dataset },
105
+ currentTarget: { id, dataset },
106
+ detail: eventDetail
111
107
  }
112
108
  handler.call(this, eventObj)
113
109
  }
114
- },
115
- __proxyEvent (e) {
116
- const eventName = e.type
117
- // 保持和微信一致
118
- e.target = e.currentTarget
119
- this.triggerEvent(eventName, {}, e)
120
110
  }
121
111
  })
122
112
  }
@@ -18,12 +18,6 @@ export default function proxyEventMixin () {
18
18
  const originValue = valuePath.reduce((acc, cur) => acc[cur], $event.detail)
19
19
  const value = filterMethod ? (innerFilter[filterMethod] ? innerFilter[filterMethod](originValue) : typeof this[filterMethod] === 'function' && this[filterMethod]) : originValue
20
20
  setByPath(this, expr, value)
21
- },
22
- __proxyEvent (e) {
23
- const type = e.type
24
- // 保持和微信一致 target 和 currentTarget 相同
25
- e.target = e.currentTarget
26
- this.triggerEvent(type, {}, e)
27
21
  }
28
22
  }
29
23
  }
@@ -1,4 +1,4 @@
1
- import { isObject } from '@mpxjs/utils'
1
+ import { getByPath, hasOwn, isObject } from '@mpxjs/utils'
2
2
 
3
3
  export default function renderHelperMixin () {
4
4
  return {
@@ -21,10 +21,21 @@ export default function renderHelperMixin () {
21
21
  }
22
22
  }
23
23
  },
24
+ // collect
24
25
  _c (key, value) {
26
+ if (hasOwn(this.__mpxProxy.renderData, key)) {
27
+ return this.__mpxProxy.renderData[key]
28
+ }
29
+ if (value === undefined) {
30
+ value = getByPath(this, key)
31
+ }
25
32
  this.__mpxProxy.renderData[key] = value
26
33
  return value
27
34
  },
35
+ // simple collect
36
+ _sc (key) {
37
+ return (this.__mpxProxy.renderData[key] = this[key])
38
+ },
28
39
  _r () {
29
40
  this.__mpxProxy.renderWithData()
30
41
  }
@@ -2,10 +2,11 @@ import transferOptions from '../core/transferOptions'
2
2
  import mergeOptions from '../core/mergeOptions'
3
3
  import builtInKeysMap from './patch/builtInKeysMap'
4
4
  import { makeMap, spreadProp, isBrowser } from '@mpxjs/utils'
5
+ import { mergeLifecycle } from '../convertor/mergeLifecycle'
5
6
  import * as webLifecycle from '../platform/patch/web/lifecycle'
6
7
  import Mpx from '../index'
7
8
 
8
- const webAppHooksMap = makeMap(webLifecycle.LIFECYCLE.APP_HOOKS)
9
+ const webAppHooksMap = makeMap(mergeLifecycle(webLifecycle.LIFECYCLE).app)
9
10
 
10
11
  function filterOptions (options, appData) {
11
12
  const newOptions = {}
@@ -84,7 +85,6 @@ export default function createApp (option, config = {}) {
84
85
  global.getApp = function () {
85
86
  if (!isBrowser) {
86
87
  console.error('[Mpx runtime error]: Dangerous API! global.getApp method is running in non browser environments')
87
- return
88
88
  }
89
89
  return appData
90
90
  }
@@ -1,8 +1,60 @@
1
- import {
2
- effectScope as vueEffectScope,
3
- getCurrentScope as vueGetCurrentScope,
4
- onScopeDispose
5
- } from 'vue'
1
+ import { EffectScope } from 'vue'
2
+ import { hasOwn } from '@mpxjs/utils'
3
+ import { PausedState } from '../../helper/const'
4
+
5
+ const hackEffectScope = () => {
6
+ EffectScope.prototype.pause = function () {
7
+ if (this.active) {
8
+ let i, l
9
+ for (i = 0, l = this.effects.length; i < l; i++) {
10
+ const effect = this.effects[i]
11
+ // vue2.7中存在对于watcher实例方法的重写(doWatch),因此无法通过修改Watcher.prototype统一实现pause和resume,只能逐个实例修改实现
12
+ if (!hasOwn(effect, 'pausedState')) {
13
+ effect.pausedState = PausedState.resumed
14
+ const rawUpdate = effect.update
15
+ effect.update = function () {
16
+ if (effect.pausedState !== PausedState.resumed) {
17
+ effect.pausedState = PausedState.dirty
18
+ } else {
19
+ rawUpdate.call(effect)
20
+ }
21
+ }
22
+ }
23
+ if (effect.pausedState !== PausedState.dirty) {
24
+ effect.pausedState = PausedState.paused
25
+ }
26
+ }
27
+ if (this.scopes) {
28
+ for (i = 0, l = this.scopes.length; i < l; i++) {
29
+ this.scopes[i].pause()
30
+ }
31
+ }
32
+ }
33
+ }
34
+
35
+ EffectScope.prototype.resume = function (ignoreDirty = false) {
36
+ if (this.active) {
37
+ let i, l
38
+ for (i = 0, l = this.effects.length; i < l; i++) {
39
+ const effect = this.effects[i]
40
+ if (hasOwn(effect, 'pausedState')) {
41
+ const lastPausedState = effect.pausedState
42
+ effect.pausedState = PausedState.resumed
43
+ if (!ignoreDirty && lastPausedState === PausedState.dirty) {
44
+ effect.update()
45
+ }
46
+ }
47
+ }
48
+ if (this.scopes) {
49
+ for (i = 0, l = this.scopes.length; i < l; i++) {
50
+ this.scopes[i].resume(ignoreDirty)
51
+ }
52
+ }
53
+ }
54
+ }
55
+ }
56
+
57
+ hackEffectScope()
6
58
 
7
59
  export {
8
60
  // watch
@@ -29,27 +81,12 @@ export {
29
81
  // computed
30
82
  computed,
31
83
  // instance
32
- getCurrentInstance
33
- } from 'vue'
34
-
35
- const noop = () => {
36
- }
37
-
38
- const fixEffectScope = (scope) => {
39
- scope.pause = noop
40
- scope.resume = noop
41
- return scope
42
- }
43
-
44
- const effectScope = (detached) => fixEffectScope(vueEffectScope(detached))
45
- const getCurrentScope = () => fixEffectScope(vueGetCurrentScope())
46
-
47
- export {
84
+ getCurrentInstance,
48
85
  // effectScope
49
86
  effectScope,
50
87
  getCurrentScope,
51
88
  onScopeDispose
52
- }
89
+ } from 'vue'
53
90
 
54
91
  export {
55
92
  // i18n
@@ -1,7 +1,7 @@
1
1
  import MpxProxy from '../../../core/proxy'
2
2
  import builtInKeysMap from '../builtInKeysMap'
3
3
  import mergeOptions from '../../../core/mergeOptions'
4
- import { isFunction, error, diffAndCloneA, hasOwn } from '@mpxjs/utils'
4
+ import { isFunction, error, diffAndCloneA, hasOwn, noop } from '@mpxjs/utils'
5
5
 
6
6
  function transformApiForProxy (context, currentInject) {
7
7
  const rawSetData = context.setData.bind(context)
@@ -45,16 +45,14 @@ function transformApiForProxy (context, currentInject) {
45
45
  }
46
46
  })
47
47
  if (currentInject) {
48
- if (currentInject.render) {
49
- Object.defineProperties(context, {
50
- __injectedRender: {
51
- get () {
52
- return currentInject.render.bind(context)
53
- },
54
- configurable: false
55
- }
56
- })
57
- }
48
+ Object.defineProperties(context, {
49
+ __injectedRender: {
50
+ get () {
51
+ return currentInject.render || noop
52
+ },
53
+ configurable: false
54
+ }
55
+ })
58
56
  if (currentInject.getRefsData) {
59
57
  Object.defineProperties(context, {
60
58
  __getRefsData: {
@@ -9,7 +9,8 @@ const COMPONENT_HOOKS = [
9
9
  'deactivated',
10
10
  'beforeDestroy',
11
11
  'destroyed',
12
- 'errorCaptured'
12
+ 'errorCaptured',
13
+ 'serverPrefetch'
13
14
  ]
14
15
 
15
16
  const PAGE_HOOKS = [
@@ -1,4 +1,4 @@
1
- import { hasOwn } from '@mpxjs/utils'
1
+ import { hasOwn, noop } from '@mpxjs/utils'
2
2
  import MpxProxy from '../../../core/proxy'
3
3
  import builtInKeysMap from '../builtInKeysMap'
4
4
  import mergeOptions from '../../../core/mergeOptions'
@@ -83,16 +83,14 @@ function transformApiForProxy (context, currentInject) {
83
83
 
84
84
  // 绑定注入的render
85
85
  if (currentInject) {
86
- if (currentInject.render) {
87
- Object.defineProperties(context, {
88
- __injectedRender: {
89
- get () {
90
- return currentInject.render
91
- },
92
- configurable: false
93
- }
94
- })
95
- }
86
+ Object.defineProperties(context, {
87
+ __injectedRender: {
88
+ get () {
89
+ return currentInject.render || noop
90
+ },
91
+ configurable: false
92
+ }
93
+ })
96
94
  if (currentInject.getRefsData) {
97
95
  Object.defineProperties(context, {
98
96
  __getRefsData: {
package/src/vuePlugin.js CHANGED
@@ -16,22 +16,22 @@ function collectDataset (attrs) {
16
16
  }
17
17
 
18
18
  export default function install (Vue) {
19
- Vue.prototype.triggerEvent = function (eventName, eventDetail, e) {
19
+ Vue.prototype.triggerEvent = function (eventName, eventDetail) {
20
+ // 输出Web时自定义组件绑定click事件会和web原生事件冲突,组件内部triggerEvent时会导致事件执行两次,将click事件改为_click来规避此问题
21
+ const escapeEvents = ['click']
22
+ if (escapeEvents.includes(eventName)) {
23
+ eventName = '_' + eventName
24
+ }
20
25
  let eventObj = {}
21
- if (e) {
22
- e.detail = Object.assign(e.detail, eventDetail)
23
- eventObj = e
24
- } else {
25
- const dataset = collectDataset(this.$attrs)
26
- const id = this.$attrs.id || ''
27
- const timeStamp = +new Date()
28
- eventObj = {
29
- type: eventName,
30
- timeStamp,
31
- target: { id, dataset, targetDataset: dataset },
32
- currentTarget: { id, dataset },
33
- detail: eventDetail
34
- }
26
+ const dataset = collectDataset(this.$attrs)
27
+ const id = this.$attrs.id || ''
28
+ const timeStamp = +new Date()
29
+ eventObj = {
30
+ type: eventName,
31
+ timeStamp,
32
+ target: { id, dataset, targetDataset: dataset },
33
+ currentTarget: { id, dataset },
34
+ detail: eventDetail
35
35
  }
36
36
  return this.$emit(eventName, eventObj)
37
37
  }