entry-framework.js
5.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
/* @flow */
// this will be preserved during build
// $flow-disable-line
const VueFactory = require('./factory')
const instanceOptions: { [key: string]: WeexInstanceOption } = {}
/**
* Create instance context.
*/
export function createInstanceContext (
instanceId: string,
runtimeContext: WeexRuntimeContext,
data: Object = {}
): WeexInstanceContext {
const weex: Weex = runtimeContext.weex
const instance: WeexInstanceOption = instanceOptions[instanceId] = {
instanceId,
config: weex.config,
document: weex.document,
data
}
// Each instance has a independent `Vue` module instance
const Vue = instance.Vue = createVueModuleInstance(instanceId, weex)
// DEPRECATED
const timerAPIs = getInstanceTimer(instanceId, weex.requireModule)
const instanceContext = Object.assign({ Vue }, timerAPIs)
Object.freeze(instanceContext)
return instanceContext
}
/**
* Destroy an instance with id. It will make sure all memory of
* this instance released and no more leaks.
*/
export function destroyInstance (instanceId: string): void {
const instance = instanceOptions[instanceId]
if (instance && instance.app instanceof instance.Vue) {
try {
instance.app.$destroy()
instance.document.destroy()
} catch (e) {}
delete instance.document
delete instance.app
}
delete instanceOptions[instanceId]
}
/**
* Refresh an instance with id and new top-level component data.
* It will use `Vue.set` on all keys of the new data. So it's better
* define all possible meaningful keys when instance created.
*/
export function refreshInstance (
instanceId: string,
data: Object
): Error | void {
const instance = instanceOptions[instanceId]
if (!instance || !(instance.app instanceof instance.Vue)) {
return new Error(`refreshInstance: instance ${instanceId} not found!`)
}
if (instance.Vue && instance.Vue.set) {
for (const key in data) {
instance.Vue.set(instance.app, key, data[key])
}
}
// Finally `refreshFinish` signal needed.
instance.document.taskCenter.send('dom', { action: 'refreshFinish' }, [])
}
/**
* Create a fresh instance of Vue for each Weex instance.
*/
function createVueModuleInstance (
instanceId: string,
weex: Weex
): GlobalAPI {
const exports = {}
VueFactory(exports, weex.document)
const Vue = exports.Vue
const instance = instanceOptions[instanceId]
// patch reserved tag detection to account for dynamically registered
// components
const weexRegex = /^weex:/i
const isReservedTag = Vue.config.isReservedTag || (() => false)
const isRuntimeComponent = Vue.config.isRuntimeComponent || (() => false)
Vue.config.isReservedTag = name => {
return (!isRuntimeComponent(name) && weex.supports(`@component/${name}`)) ||
isReservedTag(name) ||
weexRegex.test(name)
}
Vue.config.parsePlatformTagName = name => name.replace(weexRegex, '')
// expose weex-specific info
Vue.prototype.$instanceId = instanceId
Vue.prototype.$document = instance.document
// expose weex native module getter on subVue prototype so that
// vdom runtime modules can access native modules via vnode.context
Vue.prototype.$requireWeexModule = weex.requireModule
// Hack `Vue` behavior to handle instance information and data
// before root component created.
Vue.mixin({
beforeCreate () {
const options = this.$options
// root component (vm)
if (options.el) {
// set external data of instance
const dataOption = options.data
const internalData = (typeof dataOption === 'function' ? dataOption() : dataOption) || {}
options.data = Object.assign(internalData, instance.data)
// record instance by id
instance.app = this
}
},
mounted () {
const options = this.$options
// root component (vm)
if (options.el && weex.document && instance.app === this) {
try {
// Send "createFinish" signal to native.
weex.document.taskCenter.send('dom', { action: 'createFinish' }, [])
} catch (e) {}
}
}
})
/**
* @deprecated Just instance variable `weex.config`
* Get instance config.
* @return {object}
*/
Vue.prototype.$getConfig = function () {
if (instance.app instanceof Vue) {
return instance.config
}
}
return Vue
}
/**
* DEPRECATED
* Generate HTML5 Timer APIs. An important point is that the callback
* will be converted into callback id when sent to native. So the
* framework can make sure no side effect of the callback happened after
* an instance destroyed.
*/
function getInstanceTimer (
instanceId: string,
moduleGetter: Function
): Object {
const instance = instanceOptions[instanceId]
const timer = moduleGetter('timer')
const timerAPIs = {
setTimeout: (...args) => {
const handler = function () {
args[0](...args.slice(2))
}
timer.setTimeout(handler, args[1])
return instance.document.taskCenter.callbackManager.lastCallbackId.toString()
},
setInterval: (...args) => {
const handler = function () {
args[0](...args.slice(2))
}
timer.setInterval(handler, args[1])
return instance.document.taskCenter.callbackManager.lastCallbackId.toString()
},
clearTimeout: (n) => {
timer.clearTimeout(n)
},
clearInterval: (n) => {
timer.clearInterval(n)
}
}
return timerAPIs
}