Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
fix(slot): add a function to return the slot fallback content (#12014)
Co-authored-by: zrh122 <1229550935@qq.com>
  • Loading branch information
posva and zrh122 committed Apr 16, 2021
1 parent 77b5330 commit ce457f9
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 10 deletions.
2 changes: 1 addition & 1 deletion src/compiler/codegen/index.js
Expand Up @@ -547,7 +547,7 @@ export function genComment (comment: ASTText): string {
function genSlot (el: ASTElement, state: CodegenState): string {
const slotName = el.slotName || '"default"'
const children = genChildren(el, state)
let res = `_t(${slotName}${children ? `,${children}` : ''}`
let res = `_t(${slotName}${children ? `,function(){return ${children}}` : ''}`
const attrs = el.attrs || el.dynamicAttrs
? genProps((el.attrs || []).concat(el.dynamicAttrs || []).map(attr => ({
// slot props are camelized
Expand Down
20 changes: 12 additions & 8 deletions src/core/instance/render-helpers/render-slot.js
Expand Up @@ -7,26 +7,30 @@ import { extend, warn, isObject } from 'core/util/index'
*/
export function renderSlot (
name: string,
fallback: ?Array<VNode>,
fallbackRender: ?((() => Array<VNode>) | Array<VNode>),
props: ?Object,
bindObject: ?Object
): ?Array<VNode> {
const scopedSlotFn = this.$scopedSlots[name]
let nodes
if (scopedSlotFn) { // scoped slot
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
)
warn('slot v-bind without argument expects an Object', this)
}
props = extend(extend({}, bindObject), props)
}
nodes = scopedSlotFn(props) || fallback
nodes =
scopedSlotFn(props) ||
(fallbackRender &&
(Array.isArray(fallbackRender) ? fallbackRender : fallbackRender()))
} else {
nodes = this.$slots[name] || fallback
nodes =
this.$slots[name] ||
(fallbackRender &&
(Array.isArray(fallbackRender) ? fallbackRender : fallbackRender()))
}

const target = props && props.slot
Expand Down
41 changes: 41 additions & 0 deletions test/unit/features/component/component-slot.spec.js
Expand Up @@ -109,6 +109,47 @@ describe('Component slot', () => {
expect(child.$el.children[1].textContent).toBe('slot b')
})

it('it should work with previous versions of the templates', () => {
const Test = {
render() {
var _vm = this;
var _h = _vm.$createElement;
var _c = _vm._self._c || vm._h;
return _c('div', [_vm._t("default", [_c('p', [_vm._v("slot default")])])], 2)
}
}
let vm = new Vue({
template: `<test/>`,
components: { Test }
}).$mount()
expect(vm.$el.textContent).toBe('slot default')
vm = new Vue({
template: `<test>custom content</test>`,
components: { Test }
}).$mount()
expect(vm.$el.textContent).toBe('custom content')
})

it('fallback content should not be evaluated when the parent is providing it', () => {
const test = jasmine.createSpy('test')
const vm = new Vue({
template: '<test>slot default</test>',
components: {
test: {
template: '<div><slot>{{test()}}</slot></div>',
methods: {
test () {
test()
return 'test'
}
}
}
}
}).$mount()
expect(vm.$el.textContent).toBe('slot default')
expect(test).not.toHaveBeenCalled()
})

it('selector matching multiple elements', () => {
mount({
childTemplate: '<div><slot name="t"></slot></div>',
Expand Down
2 changes: 1 addition & 1 deletion test/unit/modules/compiler/codegen.spec.js
Expand Up @@ -196,7 +196,7 @@ describe('codegen', () => {
it('generate slot fallback content', () => {
assertCodegen(
'<div><slot><div>hi</div></slot></div>',
`with(this){return _c('div',[_t("default",[_c('div',[_v("hi")])])],2)}`
`with(this){return _c('div',[_t("default",function(){return [_c('div',[_v("hi")])]})],2)}`
)
})

Expand Down

1 comment on commit ce457f9

@huangrijian
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice

Please sign in to comment.