functionprocessSlot(el){if (el.tag==='slot') {el.slotName=getBindingAttr(el,'name')if (process.env.NODE_ENV!=='production'&&el.key) {warn(`\`key\` does not work on <slot> because slots are abstract outlets `+`and can possibly expand into multiple elements. `+`Use the key on a wrapping element instead.` )}}else{letslotScopeif (el.tag==='template') {slotScope=getAndRemoveAttr(el,'scope')/* istanbul ignore if */if (process.env.NODE_ENV!=='production'&&slotScope) {warn(`the "scope" attribute for scoped slots have been deprecated and `+`replaced by "slot-scope" since 2.5. The new "slot-scope" attribute `+`can also be used on plain elements in addition to <template> to `+`denote scoped slots.`,true )}el.slotScope=slotScope||getAndRemoveAttr(el,'slot-scope')}elseif ((slotScope=getAndRemoveAttr(el,'slot-scope'))) {/* istanbul ignore if */if (process.env.NODE_ENV!=='production'&&el.attrsMap['v-for']) {warn(`Ambiguous combined usage of slot-scope and v-for on <${el.tag}> `+`(v-for takes higher priority). Use a wrapper <template> for the `+`scoped slot to make it clearer.`,true )}el.slotScope=slotScope}constslotTarget=getBindingAttr(el,'slot')if (slotTarget) {el.slotTarget=slotTarget==='""'?'"default"':slotTarget // preserve slot as an attribute for native shadow DOM compat // only for non-scoped slots.if (el.tag!=='template'&&!el.slotScope) {addAttr(el,'slot',slotTarget)}}}}
if (el.slotTarget && !el.slotScope) {
data += `slot:${el.slotTarget},`
}
function processSlot (el) {
if (el.tag === 'slot') {
el.slotName = getBindingAttr(el, 'name')
}
// ...
}
function genSlot (el: ASTElement, state: CodegenState): string {
const slotName = el.slotName || '"default"'
const children = genChildren(el, state)
let res = `_t(${slotName}${children ? `,${children}` : ''}`
const attrs = el.attrs && `{${el.attrs.map(a => `${camelize(a.name)}:${a.value}`).join(',')}}`
const bind = el.attrsMap['v-bind']
if ((attrs || bind) && !children) {
res += `,null`
}
if (attrs) {
res += `,${attrs}`
}
if (bind) {
res += `${attrs ? '' : ',null'},${bind}`
}
return res + ')'
}
/**
* Runtime helper for rendering <slot>
*/
export function renderSlot (
name: string,
fallback: ?Array<VNode>,
props: ?Object,
bindObject: ?Object
): ?Array<VNode> {
const scopedSlotFn = this.$scopedSlots[name]
let nodes
if (scopedSlotFn) { // scoped slot
props = props || {}
if (bindObject) {
if (process.env.NODE_ENV !== 'production' && !isObject(bindObject)) {
warn(
'slot v-bind without argument expects an Object',
this
)
}
props = extend(extend({}, bindObject), props)
}
nodes = scopedSlotFn(props) || fallback
} else {
const slotNodes = this.$slots[name]
// warn duplicate slot usage
if (slotNodes) {
if (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
}
nodes = slotNodes || fallback
}
const target = props && props.slot
if (target) {
return this.$createElement('template', { slot: target }, nodes)
} else {
return nodes
}
}
export function initRender (vm: Component) {
// ...
const parentVnode = vm.$vnode = options._parentVnode // the placeholder node in parent tree
const renderContext = parentVnode && parentVnode.context
vm.$slots = resolveSlots(options._renderChildren, renderContext)
}
/**
* Runtime helper for resolving raw children VNodes into a slot object.
*/
export function resolveSlots (
children: ?Array<VNode>,
context: ?Component
): { [key: string]: Array<VNode> } {
const slots = {}
if (!children) {
return slots
}
for (let i = 0, l = children.length; i < l; i++) {
const child = children[i]
const data = child.data
// remove slot attribute if the node is resolved as a Vue slot node
if (data && data.attrs && data.attrs.slot) {
delete data.attrs.slot
}
// named slots should only be respected if the vnode was rendered in the
// same context.
if ((child.context === context || child.fnContext === context) &&
data && data.slot != null
) {
const name = data.slot
const slot = (slots[name] || (slots[name] = []))
if (child.tag === 'template') {
slot.push.apply(slot, child.children || [])
} else {
slot.push(child)
}
} else {
(slots.default || (slots.default = [])).push(child)
}
}
// ignore slots that contains only whitespace
for (const name in slots) {
if (slots[name].every(isWhitespace)) {
delete slots[name]
}
}
return slots
}
function processSlot (el) {
// ...
let slotScope
if (el.tag === 'template') {
slotScope = getAndRemoveAttr(el, 'scope')
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && slotScope) {
warn(
`the "scope" attribute for scoped slots have been deprecated and ` +
`replaced by "slot-scope" since 2.5. The new "slot-scope" attribute ` +
`can also be used on plain elements in addition to <template> to ` +
`denote scoped slots.`,
true
)
}
el.slotScope = slotScope || getAndRemoveAttr(el, 'slot-scope')
} else if ((slotScope = getAndRemoveAttr(el, 'slot-scope'))) {
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && el.attrsMap['v-for']) {
warn(
`Ambiguous combined usage of slot-scope and v-for on <${el.tag}> ` +
`(v-for takes higher priority). Use a wrapper <template> for the ` +
`scoped slot to make it clearer.`,
true
)
}
el.slotScope = slotScope
}
// ...
}
if (element.elseif || element.else) {
processIfConditions(element, currentParent)
} else if (element.slotScope) {
currentParent.plain = false
const name = element.slotTarget || '"default"'
;(currentParent.scopedSlots || (currentParent.scopedSlots = {}))[name] = element
} else {
currentParent.children.push(element)
element.parent = currentParent
}
export function resolveScopedSlots (
fns: ScopedSlotsData, // see flow/vnode
res?: Object
): { [key: string]: Function } {
res = res || {}
for (let i = 0; i < fns.length; i++) {
if (Array.isArray(fns[i])) {
resolveScopedSlots(fns[i], res)
} else {
res[fns[i].key] = fns[i].fn
}
}
return res
}
if (_parentVnode) {
vm.$scopedSlots = _parentVnode.data.scopedSlots || emptyObject
}