Ver Fonte

wip: scoped slot implementation

Evan You há 9 anos atrás
pai
commit
9ddbbcc340
3 ficheiros alterados com 31 adições e 12 exclusões
  1. 2 1
      flow/component.js
  2. 5 0
      src/compiler/codegen/index.js
  3. 24 11
      src/core/instance/render.js

+ 2 - 1
flow/component.js

@@ -25,6 +25,7 @@ declare interface Component {
   $children: Array<Component>;
   $refs: { [key: string]: Component | Element | Array<Component | Element> | void };
   $slots: { [key: string]: Array<VNode> };
+  $scopedSlots: ?{ [key: string]: () => VNodeChildren };
   $vnode: VNode;
   $isServer: boolean;
 
@@ -100,7 +101,7 @@ declare interface Component {
   // renderList
   _l: (val: any, render: Function) => ?Array<VNode>;
   // renderSlot
-  _t: (name: string, fallback: ?Array<VNode>) => ?Array<VNode>;
+  _t: (name: string, fallback: ?Array<VNode>, props: ?Object) => ?Array<VNode>;
   // apply v-bind object
   _b: (data: any, value: any, asProp?: boolean) => VNodeData;
   // retrive custom keyCode

+ 5 - 0
src/compiler/codegen/index.js

@@ -3,6 +3,7 @@
 import { genHandlers } from './events'
 import { baseWarn, pluckModuleFunction } from '../helpers'
 import baseDirectives from '../directives/index'
+import { camelize } from 'shared/util'
 
 // configurable state
 let warn
@@ -285,6 +286,10 @@ function genSlot (el: ASTElement): string {
   const children = genChildren(el)
   return `_t(${slotName}${
     children ? `,${children}` : ''
+  }${
+    el.attrs ? `${children ? '' : 'null'},{${
+      el.attrs.map(a => `${camelize(a.name)}:${a.value}`).join(',')
+    }}` : ''
   })`
 }
 

+ 24 - 11
src/core/instance/render.js

@@ -16,6 +16,7 @@ export function initRender (vm: Component) {
   vm._staticTrees = null
   vm._renderContext = vm.$options._parentVnode && vm.$options._parentVnode.context
   vm.$slots = resolveSlots(vm.$options._renderChildren, vm._renderContext)
+  vm.$scopedSlots = null
   // bind the public createElement fn to this instance
   // so that we get proper render context inside it.
   vm.$createElement = bind(createElement, vm)
@@ -44,6 +45,10 @@ export function renderMixin (Vue: Class<Component>) {
       }
     }
 
+    if (_parentVnode) {
+      vm.$scopedSlots = _parentVnode.data.scopedSlots
+    }
+
     if (staticRenderFns && !vm._staticTrees) {
       vm._staticTrees = []
     }
@@ -183,19 +188,27 @@ export function renderMixin (Vue: Class<Component>) {
   // renderSlot
   Vue.prototype._t = function (
     name: string,
-    fallback: ?Array<VNode>
+    fallback: ?Array<VNode>,
+    props: ?Object
   ): ?Array<VNode> {
-    const slotNodes = this.$slots[name]
-    // warn duplicate slot usage
-    if (slotNodes && process.env.NODE_ENV !== 'production') {
-      slotNodes._rendered && warn(
-        `Duplicate presence of slot "${name}" found in the same render tree ` +
-        `- this will likely cause render errors.`,
-        this
-      )
-      slotNodes._rendered = true
+    if (props) { // scoped slot
+      const scopedSlotFn = this.$scopedSlots[name]
+      return scopedSlotFn
+        ? scopedSlotFn(props) || fallback
+        : fallback
+    } else { // static slot
+      const slotNodes = this.$slots[name]
+      // warn duplicate slot usage
+      if (slotNodes && process.env.NODE_ENV !== 'production') {
+        slotNodes._rendered && warn(
+          `Duplicate presence of slot "${name}" found in the same render tree ` +
+          `- this will likely cause render errors.`,
+          this
+        )
+        slotNodes._rendered = true
+      }
+      return slotNodes || fallback
     }
-    return slotNodes || fallback
   }
 
   // apply v-bind object