vue slot-scope和v-slot

The use of slots in vue

1. What is a slot?

Official explanation: The element serves as a content distribution slot in the component template. After the content is passed in, slotthe element itself will be replaced.

A slot is a placeholder in a child component that is provided to the parent component. Indicates <slot></slot>that the parent component can fill any template code in this placeholder, such as HTML, components, etc., and the filled content will replace the <slot></slot>label of the child component .

It is equivalent to an HTML template of the component. Whether this template is displayed and how to display it is determined by the parent component.

Slot is an important mechanism of Vue components, which allows completely decoupled components to be flexibly combined.

2. Iterative changes of slots

In 2.5, the slot-scope function was introduced to be used directly on the slot element. At this time, the slot-scope can be used on any label, or it can be used as a slot on the component.

<foo> 
  <bar slot-scope = "{msg}">
    {
   
   {msg}}
  </bar> 
</foo>

The above usage leads to a problem: slot-scope does not always clearly reflect which component actually provides the scope variable. Here slot-scope is placed on the bar component, but it is actually defining the scope variable foo provided by the default slot, and it gets worse as the nesting deepens

Version 2.6 introduces a new set of template syntax v-slot for slot

The new syntax unifies ordinary slots and scoped slots under one instruction syntax, and emphasizes explicitness and consistency as a whole. At the same time, since the new syntax is fully compatible with the old syntax, this makes it possible to release it in 2.6. At this time, v-slot only works on the <template>top; there is only one exception, when the provided content is only the default slot, the component's label can be used as a slot template, and can be used directly v-sloton the component .

Why use new directive instead of fixed directive slot-scope?
  1. Using slot-scope now would be a huge change, meaning it would never be released in 2.x.
  2. Even if it is changed in 3. Therefore, something new must be introduced to distinguish it from slot-scope.
  3. In 3.x, there are plans to unify slot types, so there is no longer a need (conceptually) to differentiate between scoped and unscoped slots. A slot may or may not receive props, but they are all slots. With this conceptual unification, it seems unnecessary to treat slot and slot-scope as two special properties, and it would be better to unify the syntax under a single construct.

3. Use of slots

  • Single slot (default slot)
  • named slots
  • scoped slot
  1. Default slot (single slot/anonymous slot)
    description: The default slot refers to a slot without a name. If the child component does not define a name for the slot, the parent will fill the content of the unspecified slot into the default slot. in the trough. Default slots can be placed anywhere in the component, but there can only be one slot of this type in a component .
    The sample code is as follows:
    The subcomponent code defines a default slot:
<template>
    <div>
        <slot></slot>
    </div>
</template>

The parent component fills the default slot with content:

<template>
    <div>
        <child>
            <template>
                <h1>默认插槽内容</h1>
            </template>
        </child>
    </div>
</template>

Notice:

  • If the parent's fill content is assigned to a slot that does not have a corresponding name in the child component, the content will not be filled in the default slot.
  • If a child component doesn't have a default slot, and the parent's fill content is assigned to the default slot, then that content won't fill any of the child component's slots.
  • If a child component has multiple default slots, all fill content assigned to the default slots of the parent component will be filled in each default slot of the child component.
  1. Named slot
    Description: Named slot is actually to give the slot a name. A child component can be placed in multiple slots, and can be placed in different places, and when the parent component fills the content, it can fill the content into the corresponding slot according to the name.
    For example
    , the code of the subcomponent sets two slots (header and footer):
<template>
    <div>
        <div>
            <slot name="header"></slot>
        </div>
        <div>
            <slot name="footer"></slot>
        </div>
    </div>
</template>

The parent component fills the content. The parent component is assigned to the corresponding slot through v-slot:[name]. 2.6.0 added ( v-slot:) abbreviation replaced with characters#

<template>
    <div>
        <child>
            <template v-slot:header>
                <h1>头部内容</h1>
            </template>
            <template #footer>
                <h1>尾部内容</h1>
            </template>
            //2.6.0版本之前的写法
            <h1 slot="header">头部内容</h1>
            <h1 slot="footer">尾部内容</h1>
        </child>
    </div>
</template>

Notice:

  • If the parent's fill content is assigned to a child component without a corresponding name slot, the content will not be filled in the default slot.

  • If a child component doesn't have a default slot, and the parent's fill content is assigned to the default slot, then that content won't fill any of the child component's slots.

  1. Scope slot
    description: A scope slot is actually a slot with data, that is, a slot with parameters. Simply put, it is the parameter provided by the child component to the parent component. This parameter is only used in the slot, and the parent component The slot content can be displayed and filled in different ways according to the slot data passed by the sub-component. Scope slots require data to be bound to the slot.
    For example, the following subcomponent defines a top slot:
<div class="child4">
     <slot name="top" :data="item"></slot>
</div>
<child4>
     <template #top="slotProps">
          <div>{
   
   {slotProps.data}}</div>
     </template>
  	 <template #top="{data}">   //解构插槽 
          <div>{
   
   {data}}</div>
     </template>
</child4>

//2.6.0版本之前的使用
<div class="child3">
     <slot name="top" :data="item"></slot>
</div>
<child3>
     <div slot="top" slot-scope="slotprop">{
   
   {slotprop.data}}</div>
</child3>

One of the common scenarios
If there is a certain part of the data in the child component, each parent component will have its own set of different presentation methods for the data, then you need to use the scope slot.

4. The relationship between slot, slot-scope and v-slot, v-slot:[name] = slotProps and $slots, $scopedSlots

slots are used to access content distributed by slots; slots are used to access content distributed by slots;s l o t s is used to access the content distributed by slots ; scopedSlots is used to access scoped slots, and for each slot默认 slot including , the object contains a function that returns the corresponding VNode.

$slotsGenerally, the rendering function is not involved in the application, and it is rarely used $scopedSlots. It may be used when writing a component using the rendering function and when in-depth understanding of the implementation of the slot and the secondary packaging of the UI library.

1. Unscoped slots

<div id="app">
    <div id="parent-template">
    	<child>
        <!--2.5.11-->
        <p slot="header">header</p>
        <p slot="footer">footer</p>
        <p>default</p>
        <!--2.6.11-->
        <template v-slot:header>header</template>
        <template v-slot:footer>footer</template>
        <template>default</template>
      </child>
		</div>
</div>
<template id="child-template">
    <div>
        <slot name="header"></slot>
        <slot>默认分发处</slot>
        <slot name="footer"></slot>
    </div>
</template>
<script>
  // 注册子组件
Vue.component("child", {
   template:"#child-template",
   mounted() {
      console.log('$slots',this.$slots)
      console.log('$scopedSlots',this.$scopedSlots)
   }
});
  // 初始化父组件
new Vue({
   el: "#parent-template"
});
</script>

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-mLp09Sd7-1588226114276)(./images/slot2.5.11.jpg)]

​ v2.5.11 unscoped slot.jpg

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-4yMJ8s9w-1588226114318)(./images/slot2.6.11.jpg)]

​ v2.6.11 unscoped slot.jpg

It can be seen from this result that before v2.6.0, slot and slot-scope were separated;

Before v2.6.0, when the parent component did not call slot-scope, $scopedSlotsit was empty;

After v2.6.0, $scopedSlotsthere is a one-to-one correspondence between the named value and $slotsthe named value.

2. There are scoped slots

<div id="app">
    <div id="parent-template">
      <child>
        <!--此处是待分发的内容-->
        <!--2.5.11-->
        <p slot="header" slot-scope="{data}">{
   
   {data}}</p>
        <p slot="footer" slot-scope="scopedata">{
   
   {scopedata.data}}</p>
        <p>default</p>
        <!--2.6.11-->
        <template v-slot:header="headerdata">{
   
   {headerdata.data}}</template>
        <template v-slot:footer="footerdata">{
   
   {footerdata.data}}</template>
        <template v-slot:default>default</template>        
      </child>
    </div>
    <template id="child-template">
      <div>
        <slot name="header" :data="header"></slot>
        <slot>默认分发处</slot>
        <slot name="footer" :data="footer"></slot>
      </div>
    </template>
</div>
<script>
  // 注册子组件
Vue.component("child", {
  template:"#child-template",
  data() {
    return {
      header: '我是头部内容',
      footer: '我是底部内容'     
    }
  },
  mounted() {
    console.log('$slots',this.$slots)
    console.log('$scopedSlots',this.$scopedSlots)
  }
});
// 初始化父组件
new Vue({
    el: "#parent-template"
});
</script>

[The external link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-mtZGVuE6-1588226114334)(./images/scoped2.5.11.jpg)]

​ v2.5.11 has scoped slots.jpg

[The external link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-Yee7yZDu-1588226114338)(./images/scoped2.6.11.jpg)]

​ v2.6.11 has scoped slots.jpg

Before v2.6.0, after calling the 'header' named slot in the parent component slot-scope, $scopedSlotsthe function with 'header' as the key appeared, $slotsand the VNode with 'header' as the key disappeared;

After v2.6.0, after calling the 'header' named slot in the parent component slot-scope, $scopedSlotsthere is no change, $slotsand the VNode with 'header' as the key disappears. There was no value in it at the beginning $slots, it was stuffed in later.

3. Calling the same named slot multiple times

<div id="app">
    <div id="parent-template">
      <child>
        <template v-slot:header>
          <p>header</p>
        </template>
        <template v-slot:header>
          <p>header1</p>
        </template>
        <template v-slot:footer>
          <p>footer</p>
        </template>
        <template v-slot:default>
          <p>default</p>
        </template>
      </child>
    </div>
    <template id="child-template">
      <div>
        <slot name="header" :data="header"></slot>
        <slot>默认分发处</slot>
        <slot name="footer" :data="footer"></slot>
      </div>
    </template>
  </div>

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-uc3q5MKK-1588226114343)(./images/more-slot2.5.11.jpg)] v2.5.11 multiple calls same named slot

[The external link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-umr8LNfA-1588226114350)(./images/more-slot.jpg)]

​ v2.6.11 Multiple calls to the same named slot

It can be seen from the output that the new style of writing calls the same named slot multiple times, and the later ones will overwrite the previous ones. This is quite different from the old way of writing, so you must pay special attention when upgrading.

After the above practical comparison, we have the following conclusions:

  1. After v2.6.0, $slotsyou can get the named key in , and you can $scopedSlotsaccess it through;
  2. The writing method after v2.6.0 v-slotcannot use named slots with the same name multiple times. The later ones will overwrite the previous ones, and the contents of two named slots with the same name will not be displayed;
  3. The writing method used after v2.6.0 v-slot. If used in a subcomponent $slot, the watch method must be called, because it is $slotsempty at the beginning, and the data is inserted later.

Summarize

grammar:

Before version 2.6slot=[name] slot-scope="data"

After version 2.6, v-slot:[name] v-slot:[name]="data"although the syntax before 2.6 has been abandoned, it is also supported without error reporting.

In 3.0, this was finally removed slot-scopeand only the new syntax v-slot is supported

Performance optimization:

After version v2.6, slotand slot-scopehave been unified and integrated, turning them into functions. All slots can be this.$scopedSlotsdirectly accessed on , which makes it more convenient for us to develop advanced components.

In version 2.5, since the generated slotscope is in the parent component, slotthe update of the slot of the child component will be updated with the parent component; in 2.6, the scoped slot is a function generated during compilation. , this function will be called in the rendering function of the subcomponent after it is passed into the subcomponent. This means that the dependencies of the scoped slot will be collected by the sub-component, so when the dependency changes, it will only directly trigger the update of the sub-component, avoiding unnecessary rendering as much as possible.

Guess you like

Origin blog.csdn.net/kang_k/article/details/105860274