fix(slots): differentiate dynamic/static compiled slots

fix #1557
This commit is contained in:
Evan You
2020-07-13 12:36:41 -04:00
parent ba3b3cdda9
commit 65beba98fe
7 changed files with 143 additions and 120 deletions

View File

@@ -11,7 +11,6 @@ import {
isFunction,
EMPTY_OBJ,
ShapeFlags,
PatchFlags,
extend,
def
} from '@vue/shared'
@@ -28,6 +27,11 @@ export type InternalSlots = {
export type Slots = Readonly<InternalSlots>
export const enum CompiledSlotTypes {
STATIC = 1,
DYNAMIC = 2
}
export type RawSlots = {
[name: string]: unknown
// manual render fn hint to skip forced children updates
@@ -40,7 +44,7 @@ export type RawSlots = {
// object may be directly passed down to a child component in a manual
// render function, and the optimization hint need to be on the slot object
// itself to be preserved.
_?: 1
_?: CompiledSlotTypes
}
const isInternalKey = (key: string) => key[0] === '_' || key === '$stable'
@@ -105,10 +109,11 @@ export const initSlots = (
children: VNodeNormalizedChildren
) => {
if (instance.vnode.shapeFlag & ShapeFlags.SLOTS_CHILDREN) {
if ((children as RawSlots)._ === 1) {
const type = (children as RawSlots)._
if (type) {
instance.slots = children as InternalSlots
// make compiler marker non-enumerable
def(children as InternalSlots, '_', 1)
def(children as InternalSlots, '_', type)
} else {
normalizeObjectSlots(children as RawSlots, (instance.slots = {}))
}
@@ -129,21 +134,20 @@ export const updateSlots = (
let needDeletionCheck = true
let deletionComparisonTarget = EMPTY_OBJ
if (vnode.shapeFlag & ShapeFlags.SLOTS_CHILDREN) {
if ((children as RawSlots)._ === 1) {
const type = (children as RawSlots)._
if (type) {
// compiled slots.
if (__DEV__ && isHmrUpdating) {
// Parent was HMR updated so slot content may have changed.
// force update slots and mark instance for hmr as well
extend(slots, children as Slots)
} else if (
// bail on dynamic slots (v-if, v-for, reference of scope variables)
!(vnode.patchFlag & PatchFlags.DYNAMIC_SLOTS)
) {
} else if (type === CompiledSlotTypes.STATIC) {
// compiled AND static.
// no need to update, and skip stale slots removal.
needDeletionCheck = false
} else {
// compiled but dynamic - update slots, but skip normalization.
// compiled but dynamic (v-if/v-for on slots) - update slots, but skip
// normalization.
extend(slots, children as Slots)
}
} else {

View File

@@ -1,5 +1,5 @@
import { Data } from '../component'
import { Slots } from '../componentSlots'
import { Slots, RawSlots, CompiledSlotTypes } from '../componentSlots'
import {
VNodeArrayChildren,
openBlock,
@@ -39,7 +39,9 @@ export function renderSlot(
Fragment,
{ key: props.key },
slot ? slot(props) : fallback ? fallback() : [],
slots._ ? PatchFlags.STABLE_FRAGMENT : PatchFlags.BAIL
(slots as RawSlots)._ === CompiledSlotTypes.STATIC
? PatchFlags.STABLE_FRAGMENT
: PatchFlags.BAIL
)
)
}