mirror of
https://gitee.com/vuejs/vue.git
synced 2024-12-02 12:07:39 +08:00
feat: new scoped slot syntax implementation update per rfc
This commit is contained in:
parent
aef5b4e478
commit
c5c354d593
@ -177,6 +177,20 @@ export function getAndRemoveAttr (
|
|||||||
return val
|
return val
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getAndRemoveAttrByRegex (
|
||||||
|
el: ASTElement,
|
||||||
|
name: RegExp
|
||||||
|
) {
|
||||||
|
const list = el.attrsList
|
||||||
|
for (let i = 0, l = list.length; i < l; i++) {
|
||||||
|
const attr = list[i]
|
||||||
|
if (name.test(attr.name)) {
|
||||||
|
list.splice(i, 1)
|
||||||
|
return attr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function rangeSetItem (
|
function rangeSetItem (
|
||||||
item: any,
|
item: any,
|
||||||
range?: { start?: number, end?: number }
|
range?: { start?: number, end?: number }
|
||||||
|
@ -17,7 +17,8 @@ import {
|
|||||||
getBindingAttr,
|
getBindingAttr,
|
||||||
getAndRemoveAttr,
|
getAndRemoveAttr,
|
||||||
getRawBindingAttr,
|
getRawBindingAttr,
|
||||||
pluckModuleFunction
|
pluckModuleFunction,
|
||||||
|
getAndRemoveAttrByRegex
|
||||||
} from '../helpers'
|
} from '../helpers'
|
||||||
|
|
||||||
export const onRE = /^@|^v-on:/
|
export const onRE = /^@|^v-on:/
|
||||||
@ -31,6 +32,8 @@ export const bindRE = /^:|^\.|^v-bind:/
|
|||||||
const propBindRE = /^\./
|
const propBindRE = /^\./
|
||||||
const modifierRE = /\.[^.]+/g
|
const modifierRE = /\.[^.]+/g
|
||||||
|
|
||||||
|
const scopedSlotShorthandRE = /^:?\(.*\)$/
|
||||||
|
|
||||||
const lineBreakRE = /[\r\n]/
|
const lineBreakRE = /[\r\n]/
|
||||||
const whitespaceRE = /\s+/g
|
const whitespaceRE = /\s+/g
|
||||||
|
|
||||||
@ -568,9 +571,20 @@ function processSlotContent (el) {
|
|||||||
getAndRemoveAttr(el, 'slot-scope') ||
|
getAndRemoveAttr(el, 'slot-scope') ||
|
||||||
// new in 2.6: slot-props and its shorthand works the same as slot-scope
|
// new in 2.6: slot-props and its shorthand works the same as slot-scope
|
||||||
// when used on <template> containers
|
// when used on <template> containers
|
||||||
getAndRemoveAttr(el, 'slot-props') ||
|
getAndRemoveAttr(el, 'slot-props')
|
||||||
getAndRemoveAttr(el, '()')
|
|
||||||
)
|
)
|
||||||
|
// 2.6 shorthand syntax
|
||||||
|
const shorthand = getAndRemoveAttrByRegex(el, scopedSlotShorthandRE)
|
||||||
|
if (shorthand) {
|
||||||
|
if (process.env.NODE_ENV !== 'production' && el.slotScope) {
|
||||||
|
warn(
|
||||||
|
`Unexpected mixed usage of different slot syntaxes.`,
|
||||||
|
el
|
||||||
|
)
|
||||||
|
}
|
||||||
|
el.slotTarget = getScopedSlotShorthandName(shorthand)
|
||||||
|
el.slotScope = shorthand.value
|
||||||
|
}
|
||||||
} else if ((slotScope = getAndRemoveAttr(el, 'slot-scope'))) {
|
} else if ((slotScope = getAndRemoveAttr(el, 'slot-scope'))) {
|
||||||
/* istanbul ignore if */
|
/* istanbul ignore if */
|
||||||
if (process.env.NODE_ENV !== 'production' && el.attrsMap['v-for']) {
|
if (process.env.NODE_ENV !== 'production' && el.attrsMap['v-for']) {
|
||||||
@ -585,19 +599,29 @@ function processSlotContent (el) {
|
|||||||
el.slotScope = slotScope
|
el.slotScope = slotScope
|
||||||
} else {
|
} else {
|
||||||
// 2.6: slot-props on component, denotes default slot
|
// 2.6: slot-props on component, denotes default slot
|
||||||
slotScope = getAndRemoveAttr(el, 'slot-props') || getAndRemoveAttr(el, '()')
|
slotScope = getAndRemoveAttr(el, 'slot-props')
|
||||||
if (slotScope) {
|
const shorthand = getAndRemoveAttrByRegex(el, scopedSlotShorthandRE)
|
||||||
if (process.env.NODE_ENV !== 'production' && !maybeComponent(el)) {
|
if (slotScope || shorthand) {
|
||||||
warn(
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
`slot-props cannot be used on non-component elements.`,
|
if (!maybeComponent(el)) {
|
||||||
el.rawAttrsMap['slot-props'] || el.rawAttrsMap['()']
|
warn(
|
||||||
)
|
`slot-props cannot be used on non-component elements.`,
|
||||||
|
el.rawAttrsMap['slot-props'] || el.rawAttrsMap['()']
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (slotScope && shorthand) {
|
||||||
|
warn(
|
||||||
|
`Unexpected mixed usage of different slot syntaxes.`,
|
||||||
|
el
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// add the component's children to its default slot
|
// add the component's children to its default slot
|
||||||
const slots = el.scopedSlots || (el.scopedSlots = {})
|
const slots = el.scopedSlots || (el.scopedSlots = {})
|
||||||
const slotContainer = slots[`"default"`] = createASTElement('template', [], el)
|
const target = shorthand ? getScopedSlotShorthandName(shorthand) : `"default"`
|
||||||
|
const slotContainer = slots[target] = createASTElement('template', [], el)
|
||||||
slotContainer.children = el.children
|
slotContainer.children = el.children
|
||||||
slotContainer.slotScope = slotScope
|
slotContainer.slotScope = shorthand ? shorthand.value : slotScope
|
||||||
// remove children as they are returned from scopedSlots now
|
// remove children as they are returned from scopedSlots now
|
||||||
el.children = []
|
el.children = []
|
||||||
// mark el non-plain so data gets generated
|
// mark el non-plain so data gets generated
|
||||||
@ -617,6 +641,14 @@ function processSlotContent (el) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getScopedSlotShorthandName ({ name }) {
|
||||||
|
return name.charAt(0) === ':'
|
||||||
|
// dynamic :(name)
|
||||||
|
? name.slice(2, -1) || `"default"`
|
||||||
|
// static (name)
|
||||||
|
: `"${name.slice(1, -1) || `default`}"`
|
||||||
|
}
|
||||||
|
|
||||||
// handle <slot/> outlets
|
// handle <slot/> outlets
|
||||||
function processSlotOutlet (el) {
|
function processSlotOutlet (el) {
|
||||||
if (el.tag === 'slot') {
|
if (el.tag === 'slot') {
|
||||||
|
@ -731,5 +731,65 @@ describe('Component scoped slot', () => {
|
|||||||
// run tests for both full syntax and shorthand
|
// run tests for both full syntax and shorthand
|
||||||
runSuite('slot-props')
|
runSuite('slot-props')
|
||||||
runSuite('()')
|
runSuite('()')
|
||||||
|
|
||||||
|
it('shorthand named slots', () => {
|
||||||
|
const vm = new Vue({
|
||||||
|
template: `
|
||||||
|
<foo ()="foo">
|
||||||
|
{{ foo }}
|
||||||
|
<template (one)="one">
|
||||||
|
{{ one }}
|
||||||
|
</template>
|
||||||
|
<template (two)="two">
|
||||||
|
{{ two }}
|
||||||
|
</template>
|
||||||
|
</foo>
|
||||||
|
`,
|
||||||
|
components: { Foo }
|
||||||
|
}).$mount()
|
||||||
|
expect(vm.$el.innerHTML.replace(/\s+/g, ' ')).toMatch(`from foo default from foo one from foo two`)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shorthand without scope variable', () => {
|
||||||
|
const vm = new Vue({
|
||||||
|
template: `
|
||||||
|
<foo>
|
||||||
|
<template (one)>one</template>
|
||||||
|
<template (two)>two</template>
|
||||||
|
</foo>
|
||||||
|
`,
|
||||||
|
components: { Foo }
|
||||||
|
}).$mount()
|
||||||
|
expect(vm.$el.innerHTML.replace(/\s+/g, ' ')).toMatch(`onetwo`)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shorthand named slots on root', () => {
|
||||||
|
const vm = new Vue({
|
||||||
|
template: `
|
||||||
|
<foo (one)="one">
|
||||||
|
{{ one }}
|
||||||
|
</foo>
|
||||||
|
`,
|
||||||
|
components: { Foo }
|
||||||
|
}).$mount()
|
||||||
|
expect(vm.$el.innerHTML.replace(/\s+/g, ' ')).toMatch(`from foo one`)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('dynamic shorthand', () => {
|
||||||
|
const vm = new Vue({
|
||||||
|
data: {
|
||||||
|
a: 'one',
|
||||||
|
b: 'two'
|
||||||
|
},
|
||||||
|
template: `
|
||||||
|
<foo>
|
||||||
|
<template :(a)="one">{{ one }} </template>
|
||||||
|
<template :(b)="two">{{ two }}</template>
|
||||||
|
</foo>
|
||||||
|
`,
|
||||||
|
components: { Foo }
|
||||||
|
}).$mount()
|
||||||
|
expect(vm.$el.innerHTML.replace(/\s+/g, ' ')).toMatch(`from foo one from foo two`)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user