mirror of https://github.com/vuejs/vue.git
fix: expose v-slot slots without scope on this.$slots
fix #9421, fix #9458
This commit is contained in:
parent
ca57920edb
commit
0e8560d0fc
|
|
@ -411,7 +411,9 @@ function genScopedSlot (
|
|||
: genChildren(el, state) || 'undefined'
|
||||
: genElement(el, state)
|
||||
}}`
|
||||
return `{key:${el.slotTarget || `"default"`},fn:${fn}}`
|
||||
// reverse proxy v-slot without scope on this.$slots
|
||||
const reverseProxy = slotScope ? `` : `,proxy:true`
|
||||
return `{key:${el.slotTarget || `"default"`},fn:${fn}${reverseProxy}}`
|
||||
}
|
||||
|
||||
export function genChildren (
|
||||
|
|
|
|||
|
|
@ -11,6 +11,10 @@ export function resolveScopedSlots (
|
|||
if (Array.isArray(slot)) {
|
||||
resolveScopedSlots(slot, hasDynamicKeys, res)
|
||||
} else if (slot) {
|
||||
// marker for reverse proxying v-slot without scope on this.$slots
|
||||
if (slot.proxy) {
|
||||
slot.fn.proxy = true
|
||||
}
|
||||
res[slot.key] = slot.fn
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ export function normalizeScopedSlots (
|
|||
res = {}
|
||||
for (const key in slots) {
|
||||
if (slots[key] && key[0] !== '$') {
|
||||
res[key] = normalizeScopedSlot(slots[key])
|
||||
res[key] = normalizeScopedSlot(normalSlots, key, slots[key])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -31,9 +31,9 @@ export function normalizeScopedSlots (
|
|||
return res
|
||||
}
|
||||
|
||||
function normalizeScopedSlot(fn: Function): Function {
|
||||
return scope => {
|
||||
let res = fn(scope)
|
||||
function normalizeScopedSlot(normalSlots, key, fn) {
|
||||
const normalized = scope => {
|
||||
let res = fn(scope || {})
|
||||
res = res && typeof res === 'object' && !Array.isArray(res)
|
||||
? [res] // single vnode
|
||||
: normalizeChildren(res)
|
||||
|
|
@ -41,6 +41,17 @@ function normalizeScopedSlot(fn: Function): Function {
|
|||
? 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) {
|
||||
|
|
|
|||
|
|
@ -1059,4 +1059,33 @@ describe('Component scoped slot', () => {
|
|||
|
||||
expect(vm.$el.textContent).toBe(`fallback`)
|
||||
})
|
||||
|
||||
it('should expose v-slot without scope on this.$slots', () => {
|
||||
const vm = new Vue({
|
||||
template: `<foo><template v-slot>hello</template></foo>`,
|
||||
components: {
|
||||
foo: {
|
||||
render(h) {
|
||||
return h('div', this.$slots.default)
|
||||
}
|
||||
}
|
||||
}
|
||||
}).$mount()
|
||||
expect(vm.$el.textContent).toBe('hello')
|
||||
})
|
||||
|
||||
it('should not expose legacy syntax scoped slot on this.$slots', () => {
|
||||
const vm = new Vue({
|
||||
template: `<foo><template slot-scope="foo">hello</template></foo>`,
|
||||
components: {
|
||||
foo: {
|
||||
render(h) {
|
||||
expect(this.$slots.default).toBeUndefined()
|
||||
return h('div', this.$slots.default)
|
||||
}
|
||||
}
|
||||
}
|
||||
}).$mount()
|
||||
expect(vm.$el.textContent).toBe('')
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in New Issue