Przeglądaj źródła

naive async components

Evan You 10 lat temu
rodzic
commit
42f1301223
1 zmienionych plików z 49 dodań i 7 usunięć
  1. 49 7
      src/runtime/vdom/component.js

+ 49 - 7
src/runtime/vdom/component.js

@@ -1,14 +1,8 @@
 import Vue from '../instance/index'
 import { callHook } from '../instance/lifecycle'
-import { warn } from '../util/index'
+import { warn, isObject } from '../util/index'
 
 export default function Component (Ctor, data, parent, children) {
-  if (!Ctor) {
-    return
-  }
-  if (typeof Ctor === 'object') {
-    Ctor = Vue.extend(Ctor)
-  }
   if (process.env.NODE_ENV !== 'production' &&
     children && typeof children !== 'function') {
     warn(
@@ -17,6 +11,25 @@ export default function Component (Ctor, data, parent, children) {
       'dependencies and optimizes re-rendering.'
     )
   }
+  if (!Ctor) {
+    return
+  }
+  if (isObject(Ctor)) {
+    Ctor = Vue.extend(Ctor)
+  }
+  if (process.env.NODE_ENV !== 'production' && typeof Ctor !== 'function') {
+    warn(`Invalid Component definition: ${Ctor}`, parent)
+    return
+  }
+  // async component
+  if (!Ctor.options) {
+    if (Ctor.resolved) {
+      Ctor = Ctor.resolved
+    } else {
+      resolveAsyncComponent(Ctor, () => parent.$forceUpdate())
+      return
+    }
+  }
   // merge hooks on the placeholder node itself
   const hook = { init, insert, prepatch, destroy }
   if (data.hook) {
@@ -77,3 +90,32 @@ function prepatch (oldVnode, vnode) {
 function destroy (vnode) {
   vnode.data.child.$destroy()
 }
+
+function resolveAsyncComponent (factory, cb) {
+  if (factory.resolved) {
+    // cached
+    cb(factory.resolved)
+  } else if (factory.requested) {
+    // pool callbacks
+    factory.pendingCallbacks.push(cb)
+  } else {
+    factory.requested = true
+    const cbs = factory.pendingCallbacks = [cb]
+    factory(function resolve (res) {
+      if (isObject(res)) {
+        res = Vue.extend(res)
+      }
+      // cache resolved
+      factory.resolved = res
+      // invoke callbacks
+      for (var i = 0, l = cbs.length; i < l; i++) {
+        cbs[i](res)
+      }
+    }, function reject (reason) {
+      process.env.NODE_ENV !== 'production' && warn(
+        `Failed to resolve async component: ${factory}` +
+        (reason ? `\nReason: ${reason}` : '')
+      )
+    })
+  }
+}