123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384 |
- /* @flow */
- import { def } from 'core/util/lang'
- import { normalizeChildren } from 'core/vdom/helpers/normalize-children'
- import { emptyObject } from 'shared/util'
- export function normalizeScopedSlots (
- slots: { [key: string]: Function } | void,
- normalSlots: { [key: string]: Array<VNode> },
- prevSlots?: { [key: string]: Function } | void
- ): any {
- let res
- const hasNormalSlots = Object.keys(normalSlots).length > 0
- const isStable = slots ? !!slots.$stable : !hasNormalSlots
- const key = slots && slots.$key
- if (!slots) {
- res = {}
- } else if (slots._normalized) {
- // fast path 1: child component re-render only, parent did not change
- return slots._normalized
- } else if (
- isStable &&
- prevSlots &&
- prevSlots !== emptyObject &&
- key === prevSlots.$key &&
- !hasNormalSlots &&
- !prevSlots.$hasNormal
- ) {
- // fast path 2: stable scoped slots w/ no normal slots to proxy,
- // only need to normalize once
- return prevSlots
- } else {
- res = {}
- for (const key in slots) {
- if (slots[key] && key[0] !== '$') {
- res[key] = normalizeScopedSlot(normalSlots, key, slots[key])
- }
- }
- }
- // expose normal slots on scopedSlots
- for (const key in normalSlots) {
- if (!(key in res)) {
- res[key] = proxyNormalSlot(normalSlots, key)
- }
- }
- // avoriaz seems to mock a non-extensible $scopedSlots object
- // and when that is passed down this would cause an error
- if (slots && Object.isExtensible(slots)) {
- (slots: any)._normalized = res
- }
- def(res, '$stable', isStable)
- def(res, '$key', key)
- def(res, '$hasNormal', hasNormalSlots)
- return res
- }
- function normalizeScopedSlot(normalSlots, key, fn) {
- const normalized = function () {
- let res = arguments.length ? fn.apply(null, arguments) : fn({})
- res = res && typeof res === 'object' && !Array.isArray(res)
- ? [res] // single vnode
- : normalizeChildren(res)
- return res && (
- res.length === 0 ||
- (res.length === 1 && res[0].isComment) // #9658
- ) ? undefined
- : res
- }
- // this is a slot using the new v-slot syntax without scope. although it is
- // compiled as a scoped slot, render fn users would expect it to be present
- // on this.$slots because the usage is semantically a normal slot.
- if (fn.proxy) {
- Object.defineProperty(normalSlots, key, {
- get: normalized,
- enumerable: true,
- configurable: true
- })
- }
- return normalized
- }
- function proxyNormalSlot(slots, key) {
- return () => slots[key]
- }
|