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,9 +34,12 @@ 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,
|
||||||
|
ctx: ComponentInternalInstance | null | undefined
|
||||||
|
): Slot =>
|
||||||
|
withCtx((props: any) => {
|
||||||
if (__DEV__ && currentInstance != null) {
|
if (__DEV__ && currentInstance != null) {
|
||||||
warn(
|
warn(
|
||||||
`Slot "${key}" invoked outside of the render function: ` +
|
`Slot "${key}" invoked outside of the render function: ` +
|
||||||
@ -41,7 +48,7 @@ const normalizeSlot = (key: string, rawSlot: Function): Slot => (
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
return normalizeSlotValue(rawSlot(props))
|
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…
Reference in New Issue
Block a user