scope & slot parse
The scope slot in VUE has gone through several iterations, and different versions have different usage ways and limited scope (main indicator). Before starting the analysis, we might as well explore the use of scope slot in each period based on the axis of time.
Before you start, it’s important to be clear that a non-scoped slot simply specifies the name of the slot, so it was unchanged until V2.6.
Tip: By rule, tags with no slot=”name” attribute specify slot=”default” by default.
The evolution of scope usage
The scope era
The scope slot instruction of this era is scope. Can only be used on template elements.
<template slot="head" scope="row">
<h1>scope - {{row.name}}</h1>
</template>
Copy the code
Slot – scope
This era was characterized by freedom, and named slot instructions could be spread across all known components.
<self-component slot-scope="row" slot="header"></self-component>
<div slot-scope="row" slot="header"></div>
<template slot-scope="row" slot="header"></template>
Copy the code
V – slot time
This era is characterized by the simplicity of combining the designation of scope and slot name in a single instruction v-slot.
<div v-slot:head="row"></div>
<! -- non-scoped slot -->
<div v-slot:head></div>
Copy the code
Unload the last non-scoped slot
<div slot="header">header</div>
Copy the code
Analysis of the
Step 1: The nature of the slot
Before understanding how to parse, we need to briefly understand what the nature of the slot is, so that it is convenient for further parsing, and the goal of parsing.
Just to be clear
- For a non-scoped slot, you need to know the name of the slot and the name of the slot
render
Function. This is the ultimate parsing target for non-scoped slots. - For a scoped slot, you need to know not only the name and render function, but also the name of the variable that identifies the scope.
The above analysis shows that for non-scoped slots:
<div slot="header">header</div>
Copy the code
The required code may be as follows:
const slot = {
header: () = > {
return // VNode corresponding to the slot}}Copy the code
Naturally, for scoped slots:
<template v-slot:header="scope">
<div>{{scope.header}}</div>
</template>
Copy the code
The expected final resolution is
const slotScope = {
header: function(scope){
return // VNode corresponding to the slot}}Copy the code
As can be seen from the above analysis, what needs to be resolved here is:
- The name of the slot
header
- Slot scope object
scope
(Scope slots are required)
But because there are historical versions, you should wrap all cases in when parsing
parse
function getAndRemoveAttr(el, name) {
if(el.attrMap[name] ! =null) {
const attrList = el.attrList
for(let i = 0; i < attrList.length; i++){
if(attrList[i].name === name) {
attrList.splice(i, 1)
return el.attrMap[name]
}
}
}
}
// The environment variable identifies whether v-slot can be used
process.env.NEW_SLOT_SYNTAX = true
const slotRE = /^v-slot(:|$)|^#/
function parse(el) {
let slotScope
// Parse the scope variable name
if(el.tag === 'template'){
el.slotScope = getAndRemoveAttr(el, 'scope') || getAndRemoveAttr(el, 'slot-scope')}else if(slotScope = getAndRemoveAttr(el, 'slot-scope')){
el.slotScope = slotScope
}
// Parse the slot name
const slotTarget = getAndRemoveAttr(el, 'slot')
if(slotTarget){
el.slotTarget = slotTarget === '" "' ? '"default"' : slotTarget
}
/* 2.6 and later */
if(process.env.NEW_SLOT_SYNTAX){
if(el.tag === 'template') {// v-slot on <template>
const slotBinding = getAndRemoveAttrByRegex(el, slotRE)
if (slotBinding) {
const { name, dynamic } = getSlotName(slotBinding)
el.slotTarget = name
el.slotTargetDynamic = dynamic
el.slotScope = slotBinding.value || emptySlotScopeToken // force it into a scoped slot for perf}}else {
// Even if the v-slot is bound to the component, the content is put back into a template
const slotBinding = getAndRemoveAttrByRegex(el, slotRE)
if (slotBinding) {
const slots = el.scopedSlots || (el.scopedSlots = {})
const { name, dynamic } = getSlotName(slotBinding)
/ / will < compoentName v - slot = "XXXX" > DSDD < / a >
DSDD
const slotContainer = slots[name] = createASTElement('template'[], el) slotContainer.slotTarget = name slotContainer.slotTargetDynamic = dynamic slotContainer.children = el.children.filter((c: any) = > {
if(! c.slotScope) {// The scope slot cannot contain any other scope slot, otherwise it will be ignored
c.parent = slotContainer
return true
}
})
slotContainer.slotScope = slotBinding.value || emptySlotScopeToken
el.children = []
el.plain = false}}}}Copy the code
Code parsing
The above code is compatible with the resolution of both scoped and non-scoped slots of all vUE ages. In fact, you can see that for v-slot defined slots, whether the template content is wrapped in the template tag or not, the slot content is eventually included in the Template tag.
conclusion
The analysis shows that the way to use scoped and non-scoped slots in VUE is on the template tag.
For Scope
- Only in the
template
Use on labels - use
slot=name
Specify a name
For slot-scope
- Can be used on any legal tag
- use
slot=name
Specify a name
For V-slot
- Only in the
template
和 componentFor use on- When used on a component, it is still moved to the created
template
The label to go up and
- When used on a component, it is still moved to the created
- use
v-slot:name="scope"
To specify the name and scope variables
Because the syntax changes frequently, use the same syntax to facilitate maintenance. There are also two versions of the use of dynamic slot names
:slot="name"
,name
Is a dynamic namev-slot[dynamicSlotName]"
Or use abbreviations#[dynamicSlotName]