feat(runtime-core): set context for manual slot functions as well
This commit is contained in:
		
							parent
							
								
									ecd7ce60d5
								
							
						
					
					
						commit
						8a58dce603
					
				@ -494,6 +494,9 @@ const SetupProxyHandlers: { [key: string]: ProxyHandler<any> } = {}
 | 
				
			|||||||
      if (__DEV__) {
 | 
					      if (__DEV__) {
 | 
				
			||||||
        markAttrsAccessed()
 | 
					        markAttrsAccessed()
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					      // if the user pass the slots proxy to h(), normalizeChildren should not
 | 
				
			||||||
 | 
					      // attempt to attach ctx to the object
 | 
				
			||||||
 | 
					      if (key === '_') return 1
 | 
				
			||||||
      return instance[type][key]
 | 
					      return instance[type][key]
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    has: (instance, key) => key === SetupProxySymbol || key in instance[type],
 | 
					    has: (instance, key) => key === SetupProxySymbol || key in instance[type],
 | 
				
			||||||
 | 
				
			|||||||
@ -8,6 +8,7 @@ import {
 | 
				
			|||||||
import { isArray, isFunction, EMPTY_OBJ, ShapeFlags } from '@vue/shared'
 | 
					import { isArray, isFunction, EMPTY_OBJ, ShapeFlags } from '@vue/shared'
 | 
				
			||||||
import { warn } from './warning'
 | 
					import { warn } from './warning'
 | 
				
			||||||
import { isKeepAlive } from './components/KeepAlive'
 | 
					import { isKeepAlive } from './components/KeepAlive'
 | 
				
			||||||
 | 
					import { withCtx } from './helpers/withRenderContext'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type Slot = (...args: any[]) => VNode[]
 | 
					export type Slot = (...args: any[]) => VNode[]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -21,6 +22,9 @@ export type RawSlots = {
 | 
				
			|||||||
  [name: string]: unknown
 | 
					  [name: string]: unknown
 | 
				
			||||||
  // manual render fn hint to skip forced children updates
 | 
					  // manual render fn hint to skip forced children updates
 | 
				
			||||||
  $stable?: boolean
 | 
					  $stable?: boolean
 | 
				
			||||||
 | 
					  // internal, for tracking slot owner instance. This is attached during
 | 
				
			||||||
 | 
					  // normalizeChildren when the component vnode is created.
 | 
				
			||||||
 | 
					  _ctx?: ComponentInternalInstance | null
 | 
				
			||||||
  // internal, indicates compiler generated slots = can skip normalization
 | 
					  // internal, indicates compiler generated slots = can skip normalization
 | 
				
			||||||
  _?: 1
 | 
					  _?: 1
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -30,18 +34,21 @@ const normalizeSlotValue = (value: unknown): VNode[] =>
 | 
				
			|||||||
    ? value.map(normalizeVNode)
 | 
					    ? value.map(normalizeVNode)
 | 
				
			||||||
    : [normalizeVNode(value as VNodeChild)]
 | 
					    : [normalizeVNode(value as VNodeChild)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const normalizeSlot = (key: string, rawSlot: Function): Slot => (
 | 
					const normalizeSlot = (
 | 
				
			||||||
  props: any
 | 
					  key: string,
 | 
				
			||||||
) => {
 | 
					  rawSlot: Function,
 | 
				
			||||||
  if (__DEV__ && currentInstance != null) {
 | 
					  ctx: ComponentInternalInstance | null | undefined
 | 
				
			||||||
    warn(
 | 
					): Slot =>
 | 
				
			||||||
      `Slot "${key}" invoked outside of the render function: ` +
 | 
					  withCtx((props: any) => {
 | 
				
			||||||
        `this will not track dependencies used in the slot. ` +
 | 
					    if (__DEV__ && currentInstance != null) {
 | 
				
			||||||
        `Invoke the slot function inside the render function instead.`
 | 
					      warn(
 | 
				
			||||||
    )
 | 
					        `Slot "${key}" invoked outside of the render function: ` +
 | 
				
			||||||
  }
 | 
					          `this will not track dependencies used in the slot. ` +
 | 
				
			||||||
  return normalizeSlotValue(rawSlot(props))
 | 
					          `Invoke the slot function inside the render function instead.`
 | 
				
			||||||
}
 | 
					      )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return normalizeSlotValue(rawSlot(props))
 | 
				
			||||||
 | 
					  }, ctx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function resolveSlots(
 | 
					export function resolveSlots(
 | 
				
			||||||
  instance: ComponentInternalInstance,
 | 
					  instance: ComponentInternalInstance,
 | 
				
			||||||
@ -55,11 +62,12 @@ export function resolveSlots(
 | 
				
			|||||||
      slots = children as Slots
 | 
					      slots = children as Slots
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      slots = {}
 | 
					      slots = {}
 | 
				
			||||||
 | 
					      const ctx = rawSlots._ctx
 | 
				
			||||||
      for (const key in rawSlots) {
 | 
					      for (const key in rawSlots) {
 | 
				
			||||||
        if (key === '$stable') continue
 | 
					        if (key === '$stable' || key === '_ctx') continue
 | 
				
			||||||
        const value = rawSlots[key]
 | 
					        const value = rawSlots[key]
 | 
				
			||||||
        if (isFunction(value)) {
 | 
					        if (isFunction(value)) {
 | 
				
			||||||
          slots[key] = normalizeSlot(key, value)
 | 
					          slots[key] = normalizeSlot(key, value, ctx)
 | 
				
			||||||
        } else if (value != null) {
 | 
					        } else if (value != null) {
 | 
				
			||||||
          if (__DEV__) {
 | 
					          if (__DEV__) {
 | 
				
			||||||
            warn(
 | 
					            warn(
 | 
				
			||||||
 | 
				
			|||||||
@ -24,13 +24,12 @@ export function popScopeId() {
 | 
				
			|||||||
export function withScopeId(id: string): <T extends Function>(fn: T) => T {
 | 
					export function withScopeId(id: string): <T extends Function>(fn: T) => T {
 | 
				
			||||||
  if (__BUNDLER__) {
 | 
					  if (__BUNDLER__) {
 | 
				
			||||||
    return ((fn: Function, ctx?: ComponentInternalInstance) => {
 | 
					    return ((fn: Function, ctx?: ComponentInternalInstance) => {
 | 
				
			||||||
      function renderWithId(this: any) {
 | 
					      return withCtx(function(this: any) {
 | 
				
			||||||
        pushScopeId(id)
 | 
					        pushScopeId(id)
 | 
				
			||||||
        const res = fn.apply(this, arguments)
 | 
					        const res = fn.apply(this, arguments)
 | 
				
			||||||
        popScopeId()
 | 
					        popScopeId()
 | 
				
			||||||
        return res
 | 
					        return res
 | 
				
			||||||
      }
 | 
					      }, ctx)
 | 
				
			||||||
      return ctx ? withCtx(renderWithId, ctx) : renderWithId
 | 
					 | 
				
			||||||
    }) as any
 | 
					    }) as any
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    return undefined as any
 | 
					    return undefined as any
 | 
				
			||||||
 | 
				
			|||||||
@ -5,7 +5,11 @@ import {
 | 
				
			|||||||
  currentRenderingInstance
 | 
					  currentRenderingInstance
 | 
				
			||||||
} from '../componentRenderUtils'
 | 
					} from '../componentRenderUtils'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function withCtx(fn: Slot, ctx: ComponentInternalInstance) {
 | 
					export function withCtx(
 | 
				
			||||||
 | 
					  fn: Slot,
 | 
				
			||||||
 | 
					  ctx: ComponentInternalInstance | null | undefined
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					  if (!ctx) return fn
 | 
				
			||||||
  return function renderFnWithContext() {
 | 
					  return function renderFnWithContext() {
 | 
				
			||||||
    const owner = currentRenderingInstance
 | 
					    const owner = currentRenderingInstance
 | 
				
			||||||
    setCurrentRenderingInstance(ctx)
 | 
					    setCurrentRenderingInstance(ctx)
 | 
				
			||||||
 | 
				
			|||||||
@ -30,6 +30,7 @@ import { TransitionHooks } from './components/BaseTransition'
 | 
				
			|||||||
import { warn } from './warning'
 | 
					import { warn } from './warning'
 | 
				
			||||||
import { currentScopeId } from './helpers/scopeId'
 | 
					import { currentScopeId } from './helpers/scopeId'
 | 
				
			||||||
import { PortalImpl, isPortal } from './components/Portal'
 | 
					import { PortalImpl, isPortal } from './components/Portal'
 | 
				
			||||||
 | 
					import { currentRenderingInstance } from './componentRenderUtils'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const Fragment = (Symbol(__DEV__ ? 'Fragment' : undefined) as any) as {
 | 
					export const Fragment = (Symbol(__DEV__ ? 'Fragment' : undefined) as any) as {
 | 
				
			||||||
  __isFragment: true
 | 
					  __isFragment: true
 | 
				
			||||||
@ -387,8 +388,11 @@ export function normalizeChildren(vnode: VNode, children: unknown) {
 | 
				
			|||||||
    type = ShapeFlags.ARRAY_CHILDREN
 | 
					    type = ShapeFlags.ARRAY_CHILDREN
 | 
				
			||||||
  } else if (typeof children === 'object') {
 | 
					  } else if (typeof children === 'object') {
 | 
				
			||||||
    type = ShapeFlags.SLOTS_CHILDREN
 | 
					    type = ShapeFlags.SLOTS_CHILDREN
 | 
				
			||||||
 | 
					    if (!(children as RawSlots)._) {
 | 
				
			||||||
 | 
					      ;(children as RawSlots)._ctx = currentRenderingInstance
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  } else if (isFunction(children)) {
 | 
					  } else if (isFunction(children)) {
 | 
				
			||||||
    children = { default: children }
 | 
					    children = { default: children, _ctx: currentRenderingInstance }
 | 
				
			||||||
    type = ShapeFlags.SLOTS_CHILDREN
 | 
					    type = ShapeFlags.SLOTS_CHILDREN
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    children = String(children)
 | 
					    children = String(children)
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user