Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
fix: Add v-slot support in scopedSlots property, fix #1457 (#1485)
* feat: update scope-slot detection

* fix: fix issue with empty template tag when using v-slot

* test: add more v-slot tests
  • Loading branch information
dobromir-hristov committed Mar 23, 2020
1 parent 98b37f1 commit 4df7619
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 5 deletions.
43 changes: 38 additions & 5 deletions packages/create-instance/create-scoped-slots.js
Expand Up @@ -5,7 +5,7 @@ import { throwError } from 'shared/util'
import { VUE_VERSION } from 'shared/consts'

function isDestructuringSlotScope(slotScope: string): boolean {
return slotScope[0] === '{' && slotScope[slotScope.length - 1] === '}'
return /^{.*}$/.test(slotScope)
}

function getVueTemplateCompilerHelpers(
Expand Down Expand Up @@ -46,7 +46,36 @@ function validateEnvironment(): void {
}
}

const slotScopeRe = /<[^>]+ slot-scope=\"(.+)\"/
function isScopedSlot(slot) {
if (typeof slot === 'function') return { match: null, slot }

const slotScopeRe = /<[^>]+ slot-scope="(.+)"/
const vSlotRe = /<template v-slot(?::.+)?="(.+)"/
const shortVSlotRe = /<template #.*="(.+)"/

const hasOldSlotScope = slot.match(slotScopeRe)
const hasVSlotScopeAttr = slot.match(vSlotRe)
const hasShortVSlotScopeAttr = slot.match(shortVSlotRe)

if (hasOldSlotScope) {
return { slot, match: hasOldSlotScope }
} else if (hasVSlotScopeAttr || hasShortVSlotScopeAttr) {
// Strip v-slot and #slot attributes from `template` tag. compileToFunctions leaves empty `template` tag otherwise.
const sanitizedSlot = slot.replace(
/(<template)([^>]+)(>.+<\/template>)/,
'$1$3'
)
return {
slot: sanitizedSlot,
match: hasVSlotScopeAttr || hasShortVSlotScopeAttr
}
}
// we have no matches, so we just return
return {
slot: slot,
match: null
}
}

// Hide warning about <template> disallowed as root element
function customWarn(msg) {
Expand All @@ -70,14 +99,18 @@ export default function createScopedSlots(
for (const scopedSlotName in scopedSlotsOption) {
const slot = scopedSlotsOption[scopedSlotName]
const isFn = typeof slot === 'function'

const scopedSlotMatches = isScopedSlot(slot)

// Type check to silence flow (can't use isFn)
const renderFn =
typeof slot === 'function'
? slot
: compileToFunctions(slot, { warn: customWarn }).render
: compileToFunctions(scopedSlotMatches.slot, { warn: customWarn })
.render

const slotScope = scopedSlotMatches.match && scopedSlotMatches.match[1]

const hasSlotScopeAttr = !isFn && slot.match(slotScopeRe)
const slotScope = hasSlotScopeAttr && hasSlotScopeAttr[1]
scopedSlots[scopedSlotName] = function(props) {
let res
if (isFn) {
Expand Down
50 changes: 50 additions & 0 deletions test/specs/mounting-options/scopedSlots.spec.js
Expand Up @@ -281,6 +281,56 @@ describeWithShallowAndMount('scopedSlots', mountingMethod => {
}
)

itDoNotRunIf(
vueVersion < 2.6,
'renders scoped slot with v-slot syntax',
() => {
const TestComponent = {
data() {
return {
val: 25,
val2: 50
}
},
template:
'<div><slot :val="val"/><slot name="named" :val="val2"/></div>'
}
const wrapper = mountingMethod(TestComponent, {
scopedSlots: {
default:
'<template v-slot:default="{ val }"><p>{{ val }}</p></template>',
named:
'<template v-slot:named="prop"><p>{{ prop.val }}</p></template>'
}
})
expect(wrapper.html()).to.equal('<div>\n <p>25</p>\n <p>50</p>\n</div>')
}
)

itDoNotRunIf(
vueVersion < 2.6,
'renders scoped slot with shorthand v-slot syntax',
() => {
const TestComponent = {
data() {
return {
val: 25,
val2: 50
}
},
template:
'<div><slot :val="val"/><slot name="named" :val="val2"/></div>'
}
const wrapper = mountingMethod(TestComponent, {
scopedSlots: {
default: '<template #default="{ val }"><p>{{ val }}</p></template>',
named: '<template #named="prop"><p>{{ prop.val }}</p></template>'
}
})
expect(wrapper.html()).to.equal('<div>\n <p>25</p>\n <p>50</p>\n</div>')
}
)

itDoNotRunIf(
vueVersion < 2.5 || mountingMethod.name !== 'mount',
'renders using localVue constructor',
Expand Down

0 comments on commit 4df7619

Please sign in to comment.