1f7b63a95fe756bdadb88fc2349b66f59dadf31a9703d3a659ac1135c51882988f94be08bfa38f7537a97a0fefa085e4194787f0cec420d987a738b9d8557c 5.3 KB

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