@mpxjs/core 2.6.114-alpha.3 → 2.7.0-alpha
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/global.d.ts +1 -1
- package/@types/index.d.ts +8 -0
- package/@types/mpx-store.d.ts +45 -0
- package/package.json +2 -2
- package/src/core/mapStore.js +69 -29
- package/src/core/proxy.js +52 -17
- package/src/core/transferOptions.js +1 -1
- package/src/helper/MpxScroll/index.js +1 -7
- package/src/index.js +0 -22
- package/src/observer/computed.js +6 -4
- package/src/observer/watch.js +20 -0
- package/src/observer/watcher.js +21 -1
- package/src/platform/builtInMixins/pageStatusMixin.js +1 -1
- package/src/platform/builtInMixins/proxyEventMixin.js +30 -2
- package/src/platform/builtInMixins/refsMixin.js +3 -2
- package/src/platform/patch/ali/getDefaultOptions.js +14 -12
- package/src/platform/patch/swan/getDefaultOptions.js +17 -14
- package/src/platform/patch/tenon/getDefaultOptions.js +2 -4
- package/src/platform/patch/web/getDefaultOptions.js +16 -13
- package/src/platform/patch/wx/getDefaultOptions.js +14 -13
- package/src/runtime/createFactory.js +2 -2
- package/src/runtime/mpx.js +1 -3
package/@types/global.d.ts
CHANGED
package/@types/index.d.ts
CHANGED
|
@@ -8,6 +8,14 @@
|
|
|
8
8
|
/// <reference path="./global.d.ts" />
|
|
9
9
|
/// <reference path="./node.d.ts" />
|
|
10
10
|
|
|
11
|
+
// @ts-ignore
|
|
12
|
+
import VueI18n from 'vue-i18n'
|
|
13
|
+
|
|
14
|
+
declare module 'vue-i18n' {
|
|
15
|
+
export default interface VueI18n {
|
|
16
|
+
mergeMessages(messages: {[index: string]:VueI18n.LocaleMessageObject}): void;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
11
19
|
// declare Store types
|
|
12
20
|
type StoreOpt<S, G, M, A, D extends MpxStore.Deps> = MpxStore.StoreOpt<S, G, M, A, D>
|
|
13
21
|
|
package/@types/mpx-store.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
declare namespace MpxStore {
|
|
2
2
|
type UnboxDepField<D, F> = F extends keyof D ? D[F] : {}
|
|
3
3
|
|
|
4
|
+
interface compContext{
|
|
5
|
+
__mpxProxy: object;
|
|
6
|
+
[key: string]: any
|
|
7
|
+
}
|
|
8
|
+
|
|
4
9
|
interface Deps {
|
|
5
10
|
[key: string]: Store | StoreWithThis
|
|
6
11
|
}
|
|
@@ -88,7 +93,21 @@ declare namespace MpxStore {
|
|
|
88
93
|
mapActions(depPath: string, maps: string[]): {
|
|
89
94
|
[key: string]: (...payloads: any[]) => any
|
|
90
95
|
}
|
|
96
|
+
// 下面是新增的异步store的接口类型
|
|
97
|
+
mapStateToInstance<K extends keyof S>(maps: K[], context: compContext): void
|
|
98
|
+
mapStateToInstance(depPath: string, maps: string[], context: compContext): void
|
|
99
|
+
|
|
100
|
+
// mapState support object
|
|
101
|
+
mapStateToInstance<T extends { [key: string]: keyof GetAllMapKeys<S, D, 'state'> }>(obj: T, context: compContext): void
|
|
102
|
+
|
|
103
|
+
mapGettersToInstance<K extends keyof G>(maps: K[], context: compContext): void
|
|
104
|
+
mapGettersToInstance(depPath: string, maps: string[], context: compContext): void
|
|
105
|
+
|
|
106
|
+
mapMutationsToInstance<K extends keyof M>(maps: K[], context: compContext): Pick<GetMutations<M>, K>
|
|
107
|
+
mapMutationsToInstance(depPath: string, maps: string[], context: compContext): void
|
|
91
108
|
|
|
109
|
+
mapActionsToInstance<K extends keyof A>(maps: K[], context: compContext): Pick<GetActions<A>, K>
|
|
110
|
+
mapActionsToInstance(depPath: string, maps: string[], context: compContext): void
|
|
92
111
|
}
|
|
93
112
|
type GetComputedSetKeys<T> = {
|
|
94
113
|
[K in keyof T]: T[K] extends {
|
|
@@ -275,6 +294,32 @@ declare namespace MpxStore {
|
|
|
275
294
|
mapActions<T extends { [key: string]: string }>(obj: T): {
|
|
276
295
|
[I in keyof T]: (...payloads: any[]) => any
|
|
277
296
|
}
|
|
297
|
+
// 异步store api
|
|
298
|
+
mapStateToInstance<K extends keyof S>(maps: K[], context: compContext): void
|
|
299
|
+
mapStateToInstance<T extends string, P extends string>(depPath: P, maps: readonly T[], context: compContext):void
|
|
300
|
+
mapStateToInstance<T extends mapStateFunctionType<S & UnboxDepsField<D, 'state'>, GetComputedType<G> & UnboxDepsField<D, 'getters'>>>(obj: ThisType<any> & T, context: compContext): void
|
|
301
|
+
// Support chain derivation
|
|
302
|
+
mapStateToInstance<T extends { [key: string]: keyof GetAllMapKeys<S, D, 'state'> }>(obj: T, context: compContext): void
|
|
303
|
+
mapStateToInstance<T extends { [key: string]: keyof S }>(obj: T, context: compContext): void
|
|
304
|
+
mapStateToInstance<T extends { [key: string]: string }>(obj: T, context: compContext): void
|
|
305
|
+
|
|
306
|
+
mapGettersToInstance<K extends keyof G>(maps: K[], context: compContext): void
|
|
307
|
+
mapGettersToInstance<T extends string, P extends string>(depPath: P, maps: readonly T[], context: compContext): void
|
|
308
|
+
// Support chain derivation
|
|
309
|
+
mapGettersToInstance<T extends { [key: string]: keyof GetAllMapKeys<GetComputedType<G>, D, 'getters'> }>(obj: T, context: compContext): void
|
|
310
|
+
mapGettersToInstance<T extends { [key: string]: keyof G }>(obj: T, context: compContext): void
|
|
311
|
+
// When importing js in ts file, use this method to be compatible
|
|
312
|
+
mapGettersToInstance<T extends { [key: string]: string }>(obj: T, context: compContext): void
|
|
313
|
+
|
|
314
|
+
mapMutationsToInstance<K extends keyof M>(maps: K[], context: compContext): void
|
|
315
|
+
mapMutationsToInstance<T extends string, P extends string>(depPath: P, maps: readonly T[], context: compContext): void
|
|
316
|
+
mapMutationsToInstance<T extends { [key: string]: keyof M }>(obj: T, context: compContext): void
|
|
317
|
+
mapMutationsToInstance<T extends { [key: string]: string }>(obj: T, context: compContext): void
|
|
318
|
+
|
|
319
|
+
mapActionsToInstance<K extends keyof A>(maps: K[], context: compContext): void
|
|
320
|
+
mapActionsToInstance<T extends string, P extends string>(depPath: P, maps: readonly T[], context: compContext): void
|
|
321
|
+
mapActionsToInstance<T extends { [key: string]: keyof A }>(obj: T, context: compContext): void
|
|
322
|
+
mapActionsToInstance<T extends { [key: string]: string }>(obj: T, context: compContext): void
|
|
278
323
|
}
|
|
279
324
|
|
|
280
325
|
type StoreWithThis<S = {}, G = {}, M = {}, A = {}, D extends Deps = {}> = IStoreWithThis<S, G, M, A, D> & CompatibleDispatch
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mpxjs/core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.0-alpha",
|
|
4
4
|
"description": "mpx runtime core",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"miniprogram",
|
|
@@ -43,5 +43,5 @@
|
|
|
43
43
|
"url": "https://github.com/didi/mpx/issues"
|
|
44
44
|
},
|
|
45
45
|
"sideEffects": false,
|
|
46
|
-
"gitHead": "
|
|
46
|
+
"gitHead": "00ed5b8ad381d9b718828b5e169b1ce5cc45c3a6"
|
|
47
47
|
}
|
package/src/core/mapStore.js
CHANGED
|
@@ -3,52 +3,92 @@ import {
|
|
|
3
3
|
getByPath
|
|
4
4
|
} from '../helper/utils'
|
|
5
5
|
|
|
6
|
-
import { warn } from '../helper/log'
|
|
6
|
+
import { warn, error } from '../helper/log'
|
|
7
7
|
|
|
8
8
|
function mapFactory (type, store) {
|
|
9
9
|
return function (depPath, maps) {
|
|
10
10
|
maps = normalizeMap(depPath, maps)
|
|
11
11
|
const result = {}
|
|
12
|
-
|
|
12
|
+
Object.entries(maps).forEach(([key, value]) => {
|
|
13
13
|
result[key] = function (payload) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
14
|
+
switch (type) {
|
|
15
|
+
case 'state':
|
|
16
|
+
if (typeof value === 'function') {
|
|
17
|
+
return value.call(this, store.state, store.getters)
|
|
18
|
+
} else {
|
|
19
|
+
let stateVal = getByPath(store.state, value, '', '__NOTFOUND__')
|
|
20
|
+
if (stateVal === '__NOTFOUND__') {
|
|
21
|
+
warn(`Unknown state named [${value}].`)
|
|
22
|
+
stateVal = ''
|
|
23
|
+
}
|
|
24
|
+
return stateVal
|
|
25
|
+
}
|
|
26
|
+
case 'getters':
|
|
27
|
+
let getterVal = getByPath(store.getters, value, '', '__NOTFOUND__')
|
|
28
|
+
if (getterVal === '__NOTFOUND__') {
|
|
29
|
+
warn(`Unknown getter named [${value}].`)
|
|
30
|
+
getterVal = ''
|
|
31
|
+
}
|
|
32
|
+
return getterVal
|
|
33
|
+
case 'mutations':
|
|
34
|
+
return store.commit(value, payload)
|
|
35
|
+
case 'actions':
|
|
36
|
+
return store.dispatch(value, payload)
|
|
26
37
|
}
|
|
27
38
|
}
|
|
28
|
-
}
|
|
39
|
+
})
|
|
29
40
|
return result
|
|
30
41
|
}
|
|
31
42
|
}
|
|
32
43
|
|
|
44
|
+
function checkMapInstance (args) {
|
|
45
|
+
const context = args[args.length - 1]
|
|
46
|
+
const isValid = context && typeof context === 'object' && context.__mpxProxy
|
|
47
|
+
if (!isValid) {
|
|
48
|
+
error(`调用map**ToInstance时必须传入当前component实例this`)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
args.splice(-1)
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
restParams: args,
|
|
55
|
+
context
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
33
59
|
export default function (store) {
|
|
34
60
|
return {
|
|
35
61
|
mapGetters: mapFactory('getters', store),
|
|
36
62
|
mapMutations: mapFactory('mutations', store),
|
|
37
63
|
mapActions: mapFactory('actions', store),
|
|
38
|
-
mapState: (
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
64
|
+
mapState: mapFactory('state', store),
|
|
65
|
+
// 以下是map**ToInstance用于异步store的,参数args:depPath, maps, context
|
|
66
|
+
mapStateToInstance: (...args) => {
|
|
67
|
+
const { context, restParams } = checkMapInstance(args)
|
|
68
|
+
const mapStateFun = mapFactory('state', store)
|
|
69
|
+
const result = mapStateFun(...restParams)
|
|
70
|
+
// 将result挂载到mpxProxy实例属性上
|
|
71
|
+
context.__mpxProxy.options.computed = context.__mpxProxy.options.computed || {}
|
|
72
|
+
Object.assign(context.__mpxProxy.options.computed, result)
|
|
73
|
+
},
|
|
74
|
+
mapGettersToInstance: (...args) => {
|
|
75
|
+
const { context, restParams } = checkMapInstance(args)
|
|
76
|
+
const mapGetFun = mapFactory('getters', store)
|
|
77
|
+
const result = mapGetFun(...restParams)
|
|
78
|
+
context.__mpxProxy.options.computed = context.__mpxProxy.options.computed || {}
|
|
79
|
+
Object.assign(context.__mpxProxy.options.computed, result)
|
|
80
|
+
},
|
|
81
|
+
mapMutationsToInstance: (...args) => {
|
|
82
|
+
const { context, restParams } = checkMapInstance(args)
|
|
83
|
+
const mapMutationFun = mapFactory('mutations', store)
|
|
84
|
+
const result = mapMutationFun(...restParams)
|
|
85
|
+
Object.assign(context, result)
|
|
86
|
+
},
|
|
87
|
+
mapActionsToInstance: (...args) => {
|
|
88
|
+
const { context, restParams } = checkMapInstance(args)
|
|
89
|
+
const mapActionFun = mapFactory('actions', store)
|
|
90
|
+
const result = mapActionFun(...restParams)
|
|
91
|
+
Object.assign(context, result)
|
|
52
92
|
}
|
|
53
93
|
}
|
|
54
94
|
}
|
package/src/core/proxy.js
CHANGED
|
@@ -41,12 +41,14 @@ export default class MPXProxy {
|
|
|
41
41
|
this.uid = uid++
|
|
42
42
|
this.name = options.name || ''
|
|
43
43
|
this.options = options
|
|
44
|
-
//
|
|
45
|
-
this.state =
|
|
44
|
+
// beforeCreate -> created -> mounted -> destroyed
|
|
45
|
+
this.state = BEFORECREATE
|
|
46
46
|
this.lockTask = asyncLock()
|
|
47
47
|
this.ignoreProxyMap = makeMap(EXPORT_MPX.config.ignoreProxyWhiteList)
|
|
48
48
|
if (__mpx_mode__ !== 'web' && __mpx_mode__ !== 'tenon') {
|
|
49
49
|
this._watchers = []
|
|
50
|
+
this._namedWatchers = {}
|
|
51
|
+
this._computedWatchers = {}
|
|
50
52
|
this._watcher = null
|
|
51
53
|
this.localKeysMap = {} // 非props key
|
|
52
54
|
this.renderData = {} // 渲染函数中收集的数据
|
|
@@ -61,16 +63,33 @@ export default class MPXProxy {
|
|
|
61
63
|
this.initApi()
|
|
62
64
|
this.callUserHook(BEFORECREATE)
|
|
63
65
|
if (__mpx_mode__ !== 'web' && __mpx_mode__ !== 'tenon') {
|
|
64
|
-
this.initState(
|
|
66
|
+
this.initState()
|
|
65
67
|
}
|
|
66
68
|
this.state = CREATED
|
|
67
69
|
this.callUserHook(CREATED, params)
|
|
68
70
|
if (__mpx_mode__ !== 'web' && __mpx_mode__ !== 'tenon') {
|
|
69
|
-
|
|
70
|
-
this.options.__nativeRender__ ? this.doRender() : this.initRender()
|
|
71
|
+
this.initRender()
|
|
71
72
|
}
|
|
72
73
|
}
|
|
73
74
|
|
|
75
|
+
reCreated (params) {
|
|
76
|
+
const options = this.options
|
|
77
|
+
this.state = BEFORECREATE
|
|
78
|
+
this.callUserHook(BEFORECREATE)
|
|
79
|
+
if (__mpx_mode__ !== 'web') {
|
|
80
|
+
this.initComputed(options.computed, true)
|
|
81
|
+
this.initWatch(options.watch)
|
|
82
|
+
}
|
|
83
|
+
this.state = CREATED
|
|
84
|
+
this.callUserHook(CREATED, params)
|
|
85
|
+
if (__mpx_mode__ !== 'web') {
|
|
86
|
+
this.initRender()
|
|
87
|
+
}
|
|
88
|
+
this.nextTick(() => {
|
|
89
|
+
this.mounted()
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
|
|
74
93
|
renderTaskExecutor (isEmptyRender) {
|
|
75
94
|
if ((!this.isMounted() && this.curRenderTask) || (this.isMounted() && isEmptyRender)) {
|
|
76
95
|
return
|
|
@@ -117,6 +136,10 @@ export default class MPXProxy {
|
|
|
117
136
|
this.callUserHook(DESTROYED)
|
|
118
137
|
}
|
|
119
138
|
|
|
139
|
+
isDestroyed () {
|
|
140
|
+
return this.state === DESTROYED
|
|
141
|
+
}
|
|
142
|
+
|
|
120
143
|
initApi () {
|
|
121
144
|
// 挂载扩展属性到实例上
|
|
122
145
|
proxy(this.target, this.options.proto, Object.keys(this.options.proto), true, (key) => {
|
|
@@ -142,6 +165,12 @@ export default class MPXProxy {
|
|
|
142
165
|
// 强制执行render
|
|
143
166
|
this.target.$forceUpdate = (...rest) => this.forceUpdate(...rest)
|
|
144
167
|
this.target.$nextTick = fn => this.nextTick(fn)
|
|
168
|
+
this.target.$getPausableWatchers = () => this._watchers.filter(item => item.pausable)
|
|
169
|
+
this.target.$getWatcherByName = (name) => {
|
|
170
|
+
if (!this._namedWatchers) return null
|
|
171
|
+
return this._namedWatchers[name] || null
|
|
172
|
+
}
|
|
173
|
+
this.target.$getRenderWatcher = () => this._watcher
|
|
145
174
|
}
|
|
146
175
|
}
|
|
147
176
|
|
|
@@ -161,10 +190,15 @@ export default class MPXProxy {
|
|
|
161
190
|
this.initWatch(options.watch)
|
|
162
191
|
}
|
|
163
192
|
|
|
164
|
-
initComputed (computedOpt) {
|
|
193
|
+
initComputed (computedOpt, reInit) {
|
|
165
194
|
if (computedOpt) {
|
|
166
|
-
|
|
167
|
-
|
|
195
|
+
if (reInit) {
|
|
196
|
+
// target传递null以跳过computed挂载,仅重新初始化watchers
|
|
197
|
+
initComputed(this, null, computedOpt)
|
|
198
|
+
} else {
|
|
199
|
+
this.collectLocalKeys(computedOpt)
|
|
200
|
+
initComputed(this, this.data, computedOpt)
|
|
201
|
+
}
|
|
168
202
|
}
|
|
169
203
|
}
|
|
170
204
|
|
|
@@ -187,7 +221,9 @@ export default class MPXProxy {
|
|
|
187
221
|
})
|
|
188
222
|
Object.assign(this.data, dataFn.call(this.target))
|
|
189
223
|
}
|
|
224
|
+
// 此时data中不包括props数据
|
|
190
225
|
this.collectLocalKeys(this.data)
|
|
226
|
+
// 将props数据合并到data中
|
|
191
227
|
Object.keys(initialData).forEach((key) => {
|
|
192
228
|
if (!hasOwn(this.data, key)) {
|
|
193
229
|
// 除了data函数返回的数据外深拷贝切断引用关系,避免后续watch由于小程序内部对data赋值重复触发watch
|
|
@@ -241,9 +277,7 @@ export default class MPXProxy {
|
|
|
241
277
|
if (typeof EXPORT_MPX.config.hookErrorHandler === 'function') {
|
|
242
278
|
EXPORT_MPX.config.hookErrorHandler(e, this.target, hookName)
|
|
243
279
|
} else {
|
|
244
|
-
|
|
245
|
-
throw e
|
|
246
|
-
})
|
|
280
|
+
throw e
|
|
247
281
|
}
|
|
248
282
|
}
|
|
249
283
|
}
|
|
@@ -258,6 +292,7 @@ export default class MPXProxy {
|
|
|
258
292
|
while (i--) {
|
|
259
293
|
this._watchers[i].teardown()
|
|
260
294
|
}
|
|
295
|
+
this._watchers.length = 0
|
|
261
296
|
}
|
|
262
297
|
|
|
263
298
|
render () {
|
|
@@ -409,9 +444,10 @@ export default class MPXProxy {
|
|
|
409
444
|
}
|
|
410
445
|
|
|
411
446
|
initRender () {
|
|
412
|
-
|
|
447
|
+
if (this.options.__nativeRender__) return this.doRender()
|
|
448
|
+
|
|
413
449
|
if (this.target.__injectedRender) {
|
|
414
|
-
|
|
450
|
+
this._watcher = new Watcher(this, () => {
|
|
415
451
|
try {
|
|
416
452
|
return this.target.__injectedRender()
|
|
417
453
|
} catch (e) {
|
|
@@ -420,13 +456,12 @@ export default class MPXProxy {
|
|
|
420
456
|
}
|
|
421
457
|
this.render()
|
|
422
458
|
}
|
|
423
|
-
}, noop)
|
|
459
|
+
}, noop, { pausable: true })
|
|
424
460
|
} else {
|
|
425
|
-
|
|
461
|
+
this._watcher = new Watcher(this, () => {
|
|
426
462
|
this.render()
|
|
427
|
-
}, noop)
|
|
463
|
+
}, noop, { pausable: true })
|
|
428
464
|
}
|
|
429
|
-
this._watcher = renderWatcher
|
|
430
465
|
}
|
|
431
466
|
|
|
432
467
|
forceUpdate (data, options, callback) {
|
|
@@ -17,7 +17,7 @@ export default function transferOptions (options, type) {
|
|
|
17
17
|
}
|
|
18
18
|
if (currentInject && currentInject.injectComputed) {
|
|
19
19
|
// 编译计算属性注入
|
|
20
|
-
options.computed = Object.assign({},
|
|
20
|
+
options.computed = Object.assign({}, currentInject.injectComputed, options.computed)
|
|
21
21
|
}
|
|
22
22
|
if (currentInject && currentInject.injectOptions) {
|
|
23
23
|
// 编译option注入,优先微信中的单独配置
|
|
@@ -197,13 +197,7 @@ export default class MpxScroll {
|
|
|
197
197
|
)
|
|
198
198
|
}
|
|
199
199
|
|
|
200
|
-
pageScrollTo (
|
|
201
|
-
{
|
|
202
|
-
scrollTop,
|
|
203
|
-
selector,
|
|
204
|
-
duration = 300
|
|
205
|
-
}
|
|
206
|
-
) {
|
|
200
|
+
pageScrollTo ({ scrollTop, selector, duration = 300 }) {
|
|
207
201
|
let _scrollTop
|
|
208
202
|
|
|
209
203
|
if (isDef(scrollTop)) {
|
package/src/index.js
CHANGED
|
@@ -104,13 +104,6 @@ if (__mpx_mode__ === 'web') {
|
|
|
104
104
|
watch = vm.$watch.bind(vm)
|
|
105
105
|
const set = Vue.set.bind(Vue)
|
|
106
106
|
const del = Vue.delete.bind(Vue)
|
|
107
|
-
const remove = function (...args) {
|
|
108
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
109
|
-
error('$remove will be removed in next minor version, please use $delete instead!', this.$rawOptions && this.$rawOptions.mpxFileResource)
|
|
110
|
-
}
|
|
111
|
-
return del.apply(this, args)
|
|
112
|
-
}
|
|
113
|
-
// todo 补齐web必要api
|
|
114
107
|
APIs = {
|
|
115
108
|
createApp,
|
|
116
109
|
createPage,
|
|
@@ -124,15 +117,10 @@ if (__mpx_mode__ === 'web') {
|
|
|
124
117
|
watch,
|
|
125
118
|
use,
|
|
126
119
|
set,
|
|
127
|
-
remove,
|
|
128
120
|
delete: del,
|
|
129
121
|
getMixin,
|
|
130
122
|
implement
|
|
131
123
|
}
|
|
132
|
-
|
|
133
|
-
InstanceAPIs = {
|
|
134
|
-
$remove: remove
|
|
135
|
-
}
|
|
136
124
|
} else if (__mpx_mode__ === 'tenon') {
|
|
137
125
|
const set = (target, key, value) => {
|
|
138
126
|
return Reflect.set(target, key, value)
|
|
@@ -164,18 +152,10 @@ if (__mpx_mode__ === 'web') {
|
|
|
164
152
|
}
|
|
165
153
|
|
|
166
154
|
const vm = {}
|
|
167
|
-
|
|
168
155
|
watch = function (expOrFn, cb, options) {
|
|
169
156
|
return watchWithVm(vm, expOrFn, cb, options)
|
|
170
157
|
}
|
|
171
158
|
|
|
172
|
-
const remove = function (...args) {
|
|
173
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
174
|
-
error('$remove will be removed in next minor version, please use $delete instead!', this.$rawOptions && this.$rawOptions.mpxFileResource)
|
|
175
|
-
}
|
|
176
|
-
return del.apply(this, args)
|
|
177
|
-
}
|
|
178
|
-
|
|
179
159
|
APIs = {
|
|
180
160
|
createApp,
|
|
181
161
|
createPage,
|
|
@@ -189,7 +169,6 @@ if (__mpx_mode__ === 'web') {
|
|
|
189
169
|
watch,
|
|
190
170
|
use,
|
|
191
171
|
set,
|
|
192
|
-
remove,
|
|
193
172
|
delete: del,
|
|
194
173
|
getMixin,
|
|
195
174
|
implement
|
|
@@ -197,7 +176,6 @@ if (__mpx_mode__ === 'web') {
|
|
|
197
176
|
|
|
198
177
|
InstanceAPIs = {
|
|
199
178
|
$set: set,
|
|
200
|
-
$remove: remove,
|
|
201
179
|
$delete: del
|
|
202
180
|
}
|
|
203
181
|
}
|
package/src/observer/computed.js
CHANGED
|
@@ -20,10 +20,12 @@ export function initComputed (vm, target, computed) {
|
|
|
20
20
|
noop,
|
|
21
21
|
{ lazy: true }
|
|
22
22
|
)
|
|
23
|
-
if (
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
if (target) {
|
|
24
|
+
if (!(key in target)) {
|
|
25
|
+
defineComputed(vm, target, key, userDef)
|
|
26
|
+
} else {
|
|
27
|
+
error(`The computed key [${key}] is duplicated with data/props, please check.`, vm.options.mpxFileResource)
|
|
28
|
+
}
|
|
27
29
|
}
|
|
28
30
|
}
|
|
29
31
|
}
|
package/src/observer/watch.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { isObject, noop } from '../helper/utils'
|
|
2
|
+
import { error } from '../helper/log'
|
|
2
3
|
import Watcher from './watcher'
|
|
3
4
|
import { queueWatcher } from './scheduler'
|
|
4
5
|
|
|
@@ -19,7 +20,26 @@ export function watch (vm, expOrFn, cb, options) {
|
|
|
19
20
|
|
|
20
21
|
options = options || {}
|
|
21
22
|
options.user = true
|
|
23
|
+
|
|
24
|
+
if (options.once) {
|
|
25
|
+
const _cb = cb
|
|
26
|
+
const onceCb = typeof options.once === 'function'
|
|
27
|
+
? options.once
|
|
28
|
+
: function () { return true }
|
|
29
|
+
cb = function (...args) {
|
|
30
|
+
const res = onceCb.apply(this, args)
|
|
31
|
+
if (res) watcher.teardown()
|
|
32
|
+
_cb.apply(this, args)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
22
36
|
const watcher = new Watcher(vm, expOrFn, cb, options)
|
|
37
|
+
if (!vm._namedWatchers) vm._namedWatchers = {}
|
|
38
|
+
const name = options.name
|
|
39
|
+
if (name) {
|
|
40
|
+
if (vm._namedWatchers[name]) error(`已存在name=${name} 的 watcher,当存在多个 name 相同 watcher 时仅保留当次创建的 watcher,如需都保留请使用不同的 name!`)
|
|
41
|
+
vm._namedWatchers[name] = watcher
|
|
42
|
+
}
|
|
23
43
|
if (options.immediate) {
|
|
24
44
|
cb.call(vm.target, watcher.value)
|
|
25
45
|
} else if (options.immediateAsync) {
|
package/src/observer/watcher.js
CHANGED
|
@@ -24,6 +24,7 @@ export default class Watcher {
|
|
|
24
24
|
this.deep = !!options.deep
|
|
25
25
|
this.lazy = !!options.lazy
|
|
26
26
|
this.sync = !!options.sync
|
|
27
|
+
this.name = options.name
|
|
27
28
|
} else {
|
|
28
29
|
this.deep = this.lazy = this.sync = false
|
|
29
30
|
}
|
|
@@ -31,6 +32,10 @@ export default class Watcher {
|
|
|
31
32
|
this.id = ++uid // uid for batching
|
|
32
33
|
this.active = true
|
|
33
34
|
this.immediateAsync = false
|
|
35
|
+
// 是否暂停,默认为否
|
|
36
|
+
this.paused = false
|
|
37
|
+
// 是否可被暂停,默认为否,不可被暂停
|
|
38
|
+
this.pausable = !!(options && options.pausable) || false
|
|
34
39
|
this.dirty = this.lazy // for lazy watchers
|
|
35
40
|
this.deps = []
|
|
36
41
|
this.newDeps = []
|
|
@@ -115,7 +120,7 @@ export default class Watcher {
|
|
|
115
120
|
// 支持临时将某个异步watcher修改为sync执行,在模拟setData时使用
|
|
116
121
|
update (sync) {
|
|
117
122
|
/* istanbul ignore else */
|
|
118
|
-
if (this.lazy) {
|
|
123
|
+
if (this.lazy || this.paused) {
|
|
119
124
|
this.dirty = true
|
|
120
125
|
} else if (this.sync || sync) {
|
|
121
126
|
if (sync) dequeueWatcher(this)
|
|
@@ -125,6 +130,21 @@ export default class Watcher {
|
|
|
125
130
|
}
|
|
126
131
|
}
|
|
127
132
|
|
|
133
|
+
pause () {
|
|
134
|
+
// pausable=false 不可暂停
|
|
135
|
+
if (!this.pausable) return
|
|
136
|
+
this.paused = true
|
|
137
|
+
}
|
|
138
|
+
resume () {
|
|
139
|
+
// pausable=false 不可恢复
|
|
140
|
+
if (!this.pausable) return
|
|
141
|
+
// paused 阶段被触发,则 resume 后执行一次run
|
|
142
|
+
this.paused = false
|
|
143
|
+
if (this.dirty) {
|
|
144
|
+
this.dirty = false
|
|
145
|
+
this.run()
|
|
146
|
+
}
|
|
147
|
+
}
|
|
128
148
|
/**
|
|
129
149
|
* Scheduler job interface.
|
|
130
150
|
* Will be called by the scheduler.
|
|
@@ -35,7 +35,7 @@ export default function pageStatusMixin (mixinType) {
|
|
|
35
35
|
[CREATED] () {
|
|
36
36
|
const options = this.$rawOptions
|
|
37
37
|
const hasPageShow = options.pageShow || options.pageHide
|
|
38
|
-
const needPageLifetimes = options.pageLifetimes &&
|
|
38
|
+
const needPageLifetimes = options.pageLifetimes && __mpx_mode__ === 'ali'
|
|
39
39
|
|
|
40
40
|
if (hasPageShow || needPageLifetimes) {
|
|
41
41
|
let currentPage
|
|
@@ -70,10 +70,13 @@ export default function proxyEventMixin () {
|
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
if (__mpx_mode__ === 'ali') {
|
|
73
|
+
const getHandler = (eventName, props) => {
|
|
74
|
+
const handlerName = eventName.replace(/^./, matched => matched.toUpperCase()).replace(/-([a-z])/g, (match, p1) => p1.toUpperCase())
|
|
75
|
+
return props && (props['on' + handlerName] || props['catch' + handlerName])
|
|
76
|
+
}
|
|
73
77
|
Object.assign(methods, {
|
|
74
78
|
triggerEvent (eventName, eventDetail) {
|
|
75
|
-
const
|
|
76
|
-
const handler = this.props && (this.props['on' + handlerName] || this.props['catch' + handlerName])
|
|
79
|
+
const handler = getHandler(eventName, this.props)
|
|
77
80
|
if (handler && typeof handler === 'function') {
|
|
78
81
|
const dataset = collectDataset(this.props)
|
|
79
82
|
const id = this.props.id || ''
|
|
@@ -92,6 +95,31 @@ export default function proxyEventMixin () {
|
|
|
92
95
|
},
|
|
93
96
|
detail: eventDetail
|
|
94
97
|
}
|
|
98
|
+
handler.call(this, eventObj)
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
__proxyEvent (e) {
|
|
102
|
+
const type = e.type
|
|
103
|
+
const handler = getHandler(type, this.props)
|
|
104
|
+
|
|
105
|
+
if (handler && typeof handler === 'function') {
|
|
106
|
+
const dataset = collectDataset(this.props)
|
|
107
|
+
const id = this.props.id || ''
|
|
108
|
+
const targetData = Object.assign({}, e.target || {}, {
|
|
109
|
+
id,
|
|
110
|
+
dataset
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
const currentTargetData = Object.assign({}, e.currentTarget || {}, {
|
|
114
|
+
id,
|
|
115
|
+
dataset
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
const eventObj = Object.assign({}, e, {
|
|
119
|
+
target: targetData,
|
|
120
|
+
currentTarget: currentTargetData
|
|
121
|
+
})
|
|
122
|
+
|
|
95
123
|
handler.call(this, eventObj)
|
|
96
124
|
}
|
|
97
125
|
}
|
|
@@ -22,7 +22,8 @@ const setComponentRef = function (target, ref, context, isAsync) {
|
|
|
22
22
|
enumerable: true,
|
|
23
23
|
configurable: true,
|
|
24
24
|
get () {
|
|
25
|
-
|
|
25
|
+
// wx由于分包异步化的存在,每次访问refs都需要重新执行selectComponen,避免一直拿到缓存中的placeholder
|
|
26
|
+
if (__mpx_mode__ === 'wx' || !cacheRef) {
|
|
26
27
|
return (cacheRef = context.__getRefNode(ref, isAsync))
|
|
27
28
|
}
|
|
28
29
|
return cacheRef
|
|
@@ -91,7 +92,7 @@ export default function getRefsMixin () {
|
|
|
91
92
|
}
|
|
92
93
|
const component = e.detail.component
|
|
93
94
|
const destroyed = e.detail.destroyed
|
|
94
|
-
const className = component.props.
|
|
95
|
+
const className = component.props.className || component.className
|
|
95
96
|
const identifiers = className ? className.trim().split(/\s+/).map(item => {
|
|
96
97
|
return `.${item}`
|
|
97
98
|
}) : []
|
|
@@ -84,23 +84,24 @@ function filterOptions (options, type) {
|
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
function initProxy (context, rawOptions, currentInject, params) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
87
|
+
if (!context.__mpxProxy) {
|
|
88
|
+
// 提供代理对象需要的api
|
|
89
|
+
transformApiForProxy(context, currentInject)
|
|
90
|
+
// 缓存options
|
|
91
|
+
context.$rawOptions = rawOptions
|
|
92
|
+
// 创建proxy对象
|
|
93
|
+
context.__mpxProxy = new MPXProxy(rawOptions, context)
|
|
94
|
+
context.__mpxProxy.created(params)
|
|
95
|
+
} else if (context.__mpxProxy.isDestroyed()) {
|
|
96
|
+
context.__mpxProxy.reCreated(params)
|
|
97
|
+
}
|
|
95
98
|
}
|
|
96
99
|
|
|
97
100
|
export function getDefaultOptions (type, { rawOptions = {}, currentInject }) {
|
|
98
101
|
const hookNames = type === 'component' ? ['onInit', 'didMount', 'didUnmount'] : ['onLoad', 'onReady', 'onUnload']
|
|
99
102
|
const rootMixins = [{
|
|
100
103
|
[hookNames[0]] (...params) {
|
|
101
|
-
|
|
102
|
-
initProxy(this, rawOptions, currentInject, params)
|
|
103
|
-
}
|
|
104
|
+
initProxy(this, rawOptions, currentInject, params)
|
|
104
105
|
},
|
|
105
106
|
deriveDataFromProps (nextProps) {
|
|
106
107
|
if (this.__mpxProxy && this.__mpxProxy.isMounted() && nextProps && nextProps !== this.props) {
|
|
@@ -130,6 +131,7 @@ export function getDefaultOptions (type, { rawOptions = {}, currentInject }) {
|
|
|
130
131
|
},
|
|
131
132
|
didUpdate () {
|
|
132
133
|
if (this.__mpxProxy) {
|
|
134
|
+
// todo: lockTask必要性待验证,属性更新触发自身setData时,updated执行与wx对齐,updated触发机制也考虑与wx对齐(props update && setData callback)
|
|
133
135
|
this.__mpxProxy.lockTask(() => {
|
|
134
136
|
this.__mpxProxy.updated()
|
|
135
137
|
})
|
|
@@ -143,7 +145,7 @@ export function getDefaultOptions (type, { rawOptions = {}, currentInject }) {
|
|
|
143
145
|
}
|
|
144
146
|
},
|
|
145
147
|
[hookNames[2]] () {
|
|
146
|
-
this.__mpxProxy
|
|
148
|
+
if (this.__mpxProxy) this.__mpxProxy.destroyed()
|
|
147
149
|
}
|
|
148
150
|
}]
|
|
149
151
|
rawOptions.mixins = rawOptions.mixins ? rootMixins.concat(rawOptions.mixins) : rootMixins
|
|
@@ -2,29 +2,32 @@ import mergeOptions from '../../../core/mergeOptions'
|
|
|
2
2
|
import { initProxy, filterOptions } from '../wx/getDefaultOptions'
|
|
3
3
|
|
|
4
4
|
export function getDefaultOptions (type, { rawOptions = {}, currentInject }) {
|
|
5
|
-
|
|
6
|
-
// 构造页面时统一使用onInit进行初始化
|
|
7
|
-
if (type === 'page') {
|
|
8
|
-
hookNames[0] = 'onInit'
|
|
9
|
-
}
|
|
5
|
+
let hookNames = ['attached', 'ready', 'detached']
|
|
10
6
|
// 当用户传入page作为构造器构造页面时,修改所有关键hooks
|
|
11
7
|
if (rawOptions.__pageCtor__) {
|
|
12
|
-
hookNames
|
|
13
|
-
hookNames[2] = 'onUnload'
|
|
8
|
+
hookNames = ['onLoad', 'onReady', 'onUnload']
|
|
14
9
|
}
|
|
15
|
-
|
|
10
|
+
|
|
11
|
+
const rootMixin = {
|
|
16
12
|
[hookNames[0]] (...params) {
|
|
17
|
-
|
|
18
|
-
initProxy(this, rawOptions, currentInject, params)
|
|
19
|
-
}
|
|
13
|
+
initProxy(this, rawOptions, currentInject, params)
|
|
20
14
|
},
|
|
21
15
|
[hookNames[1]] () {
|
|
22
|
-
this.__mpxProxy
|
|
16
|
+
if (this.__mpxProxy) this.__mpxProxy.mounted()
|
|
23
17
|
},
|
|
24
18
|
[hookNames[2]] () {
|
|
25
|
-
this.__mpxProxy
|
|
19
|
+
if (this.__mpxProxy) this.__mpxProxy.destroyed()
|
|
26
20
|
}
|
|
27
|
-
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// 如构造页面,优先使用onInit进行初始化
|
|
24
|
+
if (type === 'page') {
|
|
25
|
+
rootMixin.onInit = function (...params) {
|
|
26
|
+
initProxy(this, rawOptions, currentInject, params)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const rootMixins = [rootMixin]
|
|
28
31
|
rawOptions.mixins = rawOptions.mixins ? rootMixins.concat(rawOptions.mixins) : rootMixins
|
|
29
32
|
rawOptions = mergeOptions(rawOptions, type, false)
|
|
30
33
|
return filterOptions(rawOptions)
|
|
@@ -9,7 +9,6 @@ function filterOptions (options) {
|
|
|
9
9
|
if (builtInKeysMap[key]) {
|
|
10
10
|
return
|
|
11
11
|
}
|
|
12
|
-
// Tenon 使用的Vue3 语法中 data 配置需要为一个函数
|
|
13
12
|
if (key === 'data' || key === 'dataFn') {
|
|
14
13
|
newOptions.data = function mergeFn () {
|
|
15
14
|
return Object.assign(
|
|
@@ -28,8 +27,7 @@ function initProxy (context, rawOptions) {
|
|
|
28
27
|
// 缓存options
|
|
29
28
|
context.$rawOptions = rawOptions
|
|
30
29
|
// 创建proxy对象
|
|
31
|
-
|
|
32
|
-
context.__mpxProxy = mpxProxy
|
|
30
|
+
context.__mpxProxy = new MPXProxy(rawOptions, context)
|
|
33
31
|
context.__mpxProxy.created(Hummer.pageInfo && Hummer.pageInfo.params && [Hummer.pageInfo.params])
|
|
34
32
|
}
|
|
35
33
|
|
|
@@ -38,7 +36,7 @@ export function getDefaultOptions (type, { rawOptions = {}, currentInject }) {
|
|
|
38
36
|
const rootMixins = [{
|
|
39
37
|
[hookNames[0]] (...params) {
|
|
40
38
|
if (!this.__mpxProxy) {
|
|
41
|
-
initProxy(this, rawOptions, currentInject, params)
|
|
39
|
+
initProxy(this, rawOptions, currentInject, params) // todo 确认参数是否需要
|
|
42
40
|
}
|
|
43
41
|
},
|
|
44
42
|
[hookNames[1]] () {
|
|
@@ -24,30 +24,33 @@ function filterOptions (options) {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
function initProxy (context, rawOptions, params) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
if (!context.__mpxProxy) {
|
|
28
|
+
// 缓存options
|
|
29
|
+
context.$rawOptions = rawOptions
|
|
30
|
+
// 创建proxy对象
|
|
31
|
+
context.__mpxProxy = new MPXProxy(rawOptions, context)
|
|
32
|
+
context.__mpxProxy.created(params)
|
|
33
|
+
} else if (context.__mpxProxy.isDestroyed()) {
|
|
34
|
+
context.__mpxProxy.reCreated(params)
|
|
35
|
+
}
|
|
33
36
|
}
|
|
34
37
|
|
|
35
38
|
export function getDefaultOptions (type, { rawOptions = {} }) {
|
|
36
39
|
const rootMixins = [{
|
|
37
40
|
created () {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
const query = (global.__mpxRouter && global.__mpxRouter.currentRoute && global.__mpxRouter.currentRoute.query) || {}
|
|
42
|
+
initProxy(this, rawOptions, [query])
|
|
43
|
+
// web中单独触发onLoad
|
|
44
|
+
this.onLoad && this.onLoad(query)
|
|
42
45
|
},
|
|
43
46
|
mounted () {
|
|
44
|
-
this.__mpxProxy
|
|
47
|
+
if (this.__mpxProxy) this.__mpxProxy.mounted()
|
|
45
48
|
},
|
|
46
49
|
updated () {
|
|
47
|
-
this.__mpxProxy
|
|
50
|
+
if (this.__mpxProxy) this.__mpxProxy.updated()
|
|
48
51
|
},
|
|
49
52
|
destroyed () {
|
|
50
|
-
this.__mpxProxy
|
|
53
|
+
if (this.__mpxProxy) this.__mpxProxy.destroyed()
|
|
51
54
|
}
|
|
52
55
|
}]
|
|
53
56
|
// 为了在builtMixin中可以使用某些rootMixin实现的特性(如数据响应等),此处builtInMixin在rootMixin之后执行,但是当builtInMixin使用存在对应内建生命周期的目标平台声明周期写法时,可能会出现用户生命周期比builtInMixin中的生命周期先执行的情况,为了避免这种情况发生,builtInMixin应该尽可能使用内建生命周期来编写
|
|
@@ -117,14 +117,17 @@ export function filterOptions (options) {
|
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
export function initProxy (context, rawOptions, currentInject, params) {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
120
|
+
if (!context.__mpxProxy) {
|
|
121
|
+
// 提供代理对象需要的api
|
|
122
|
+
transformApiForProxy(context, currentInject)
|
|
123
|
+
// 缓存options
|
|
124
|
+
context.$rawOptions = rawOptions
|
|
125
|
+
// 创建proxy对象
|
|
126
|
+
context.__mpxProxy = new MPXProxy(rawOptions, context)
|
|
127
|
+
context.__mpxProxy.created(params)
|
|
128
|
+
} else if (context.__mpxProxy.isDestroyed()) {
|
|
129
|
+
context.__mpxProxy.reCreated(params)
|
|
130
|
+
}
|
|
128
131
|
}
|
|
129
132
|
|
|
130
133
|
export function getDefaultOptions (type, { rawOptions = {}, currentInject }) {
|
|
@@ -137,15 +140,13 @@ export function getDefaultOptions (type, { rawOptions = {}, currentInject }) {
|
|
|
137
140
|
}
|
|
138
141
|
const rootMixins = [{
|
|
139
142
|
[hookNames[0]] (...params) {
|
|
140
|
-
|
|
141
|
-
initProxy(this, rawOptions, currentInject, params)
|
|
142
|
-
}
|
|
143
|
+
initProxy(this, rawOptions, currentInject, params)
|
|
143
144
|
},
|
|
144
145
|
[hookNames[1]] () {
|
|
145
|
-
this.__mpxProxy
|
|
146
|
+
if (this.__mpxProxy) this.__mpxProxy.mounted()
|
|
146
147
|
},
|
|
147
148
|
[hookNames[2]] () {
|
|
148
|
-
this.__mpxProxy
|
|
149
|
+
if (this.__mpxProxy) this.__mpxProxy.destroyed()
|
|
149
150
|
}
|
|
150
151
|
}]
|
|
151
152
|
rawOptions.mixins = rawOptions.mixins ? rootMixins.concat(rawOptions.mixins) : rootMixins
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
const mpx = require('../index').default
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
module.exports = (type) => (...args) => {
|
|
4
4
|
if (type === 'Behavior') {
|
|
5
5
|
if (args[0]) {
|
|
6
6
|
Object.defineProperty(args[0], '__mpx_behaviors_to_mixins__', {
|
package/src/runtime/mpx.js
CHANGED