UNPKG

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