Browse Source

children render context

Evan You 10 years ago
parent
commit
c16fc2c427
3 changed files with 27 additions and 14 deletions
  1. 1 1
      src/compiler/codegen/index.js
  2. 24 12
      src/runtime/instance/render.js
  3. 2 1
      src/runtime/vdom/create-element.js

+ 1 - 1
src/compiler/codegen/index.js

@@ -102,7 +102,7 @@ function genChildren (el, asThunk) {
   }
   const code = '[' + el.children.map(genNode).join(',') + ']'
   return asThunk
-    ? `function(){return ${code}}`
+    ? `_withContext(function(){return ${code}})`
     : code
 }
 

+ 24 - 12
src/runtime/instance/render.js

@@ -5,7 +5,8 @@ import { callHook } from './lifecycle'
 import { getPropValue } from './state'
 
 export const renderState = {
-  activeInstance: null
+  activeInstance: null,
+  context: null
 }
 
 export function initRender (vm) {
@@ -58,28 +59,39 @@ export function renderMixin (Vue) {
     }
   }
 
+  /**
+   * Call a render function with this instance as the context.
+   * This is used to wrap all children thunks in codegen.
+   */
+
+  Vue.prototype._withContext = function (fn) {
+    return () => {
+      const prev = renderState.context
+      renderState.context = this
+      return fn()
+      renderState.context = prev
+    }
+  }
+
   Vue.prototype._render = function () {
-    const {
-      render,
-      _renderKey,
-      _renderData,
-      _renderChildren
-    } = this.$options
-    // resolve slots
+    const prev = renderState.activeInstance
+    renderState.activeInstance = this
+    const { render, _renderKey, _renderData, _renderChildren } = this.$options
+    // resolve slots. becaues slots are rendered in parent scope,
+    // we set the activeInstance to parent.
     if (_renderChildren) {
       resolveSlots(this, _renderChildren)
     }
-    // render
-    const prev = renderState.activeInstance
-    renderState.activeInstance = this
+    // render self
     const vnode = render.call(this)
-    renderState.activeInstance = prev
     // set key
     vnode.key = _renderKey
     // update parent data
     if (_renderData) {
       mergeParentData(this, vnode.data, _renderData)
     }
+    // restore render state
+    renderState.activeInstance = prev
     return vnode
   }
 

+ 2 - 1
src/runtime/vdom/create-element.js

@@ -11,11 +11,12 @@ import {
 
 export default function createElement (tag, data, children) {
   const parent = renderState.activeInstance
+  const context = renderState.context || parent
   if (typeof tag === 'string') {
     let Ctor
     if (isReservedTag(tag)) {
       return VNode(tag, data, flatten(children))
-    } else if ((Ctor = resolveAsset(parent.$options, 'components', tag))) {
+    } else if ((Ctor = resolveAsset(context.$options, 'components', tag))) {
       return Component(Ctor, data, parent, children)
     } else {
       if (process.env.NODE_ENV !== 'production' && !data.svg) {