vue读到的一些文章玄机随录

Vue之深入理解插槽—slot, slot-scope, v-s

2020-01-07  本文已影响0人  Coding_Life
Vue 2.6.0 以前 Vue 2.6.0 以后
具名插槽 slot 具名插槽 v-slot
作用域插槽 slot-scope = slotProps 作用域插槽 v-slot: [name] = slotProps

这里我们要讨论的不是怎么用,而是比较少有探究的 slot, slot-scope 以及 v-slot, v-slot:[name] = slotProps$slots, $scopedSlots 的关系,一般在应用中不涉及渲染函数,很少用得到$slots$scopedSlots,但是在深入理解插槽的实现和二次封装 UI库 的时候就可能用得上了。

一、 slotslot-scope$slots, $scopedSlots 的关系

1. 无作用域插槽

HTML

<div id="parent-template">
    <child>
        <!--此处是待分发的内容-->
        <p slot="header">header</p>
        <p slot="footer">footer</p>
        <p>default</p>
    </child>
</div>

<template id="child-template">
     <div>
        <slot name="header"></slot>
        <slot>默认分发处</slot>
        <slot name="footer"></slot>
    </div>
</template>

JS

// 注册子组件
Vue.component("child", {
    template:"#child-template",
  mounted() {
    console.log('$slots',this.$slots)
    console.log('$scopedSlots',this.$scopedSlots)
  }
});

// 初始化父组件
new Vue({
    el: "#parent-template"
});

Console 输出

v2.5.22无作用域插槽.png v2.6.10无作用域插槽.png

这是一个常用的插槽模板,从这个结果中可以看出v2.6.0以前,slot 和 slot-scope是分开的 ;

v2.6.0以前父组件没有调用 slot-scope 时, $scopedSlots 里面为空 ;

v2.6.0以后 $scopedSlots 里的具名值和 $slots 具名值是一一对应的。

2. 有作用域插槽

HTML

<div id="parent-template">
    <child>
        <!--此处是待分发的内容-->
        <p slot="header" slot-scope="{header}">{{ header }}</p>
        <p slot="footer">footer</p>
        <p>default</p>
    </child>
</div>

<template id="child-template">
     <div>
        <slot name="header" v-bind:header="'header'"></slot>
        <slot>默认分发处</slot>
        <slot name="footer" v-bind:footer="'footer'"></slot>
    </div>
</template>
v2.5.22有作用域插槽.png v2.6.10有作用域插槽

v2.6.0以前,在父组件中'header'具名插槽中调用了slot-scope后,$scopedSlots 中出现了‘header’为key的function, $slots 中‘header’为key的VNode不见了;

v2.6.0以后,在父组件中'header'具名插槽中调用了slot-scope后,$scopedSlots 中没有变化, $slots 中‘header’为key的VNode不见了。

3. 多次调用同一个具名插槽

HTML

<div id="parent-template">
    <child>
        <!--此处是待分发的内容-->
        <p slot="header">header</p>
    <div slot="header">header1</div>
        <p slot="footer">footer</p>
        <p>default</p>
    </child>
</div>

<template id="child-template">
     <div>
        <slot name="header" v-bind:header="'header'"></slot>
        <slot>默认分发处</slot>
        <slot name="footer" v-bind:footer="'footer'"></slot>
    </div>
</template>

Console 输出

v2.5.22 多次调用同一个具名插槽.png v2.6.·0 多次调用同一个具名插槽.png

从输出结果可以看出老式写法在v2.6.0以前和以后都能在$slots里有两个header的具名插槽内容,这与后面新式写法就有不同。

二、v-slot, v-slot:[name]=slotProps$slots, $scopedSlots 的关系

1. 无作用域插槽

HTML

<div id="parent-template">
  <child>
  <!--此处是待分发的内容-->
    <template v-slot:header>
      <p>{{ header }}</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"></slot>
        <slot>默认分发处</slot>
        <slot name="footer"></slot>
    </div>
</template>

Console输出

v2.6.10 具名插槽.png

从输出可以看出,新式写法在v2.6.0版本后,default中tag 为 undfined的元素没有了,并且$slots中的内容是后面塞进去的,$scopedSlots一开始就有。

2. 有作用域插槽

HTML

<div id="parent-template">
  <child>
  <!--此处是待分发的内容-->
    <template v-slot:header="{header}">
      <p>{{ header }}</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" v-bind:header="'header'"></slot>
        <slot>默认分发处</slot>
        <slot name="footer" v-bind:header="'footer'"></slot>
    </div>
</template>

Console 输出


v2.6.10 作用域插槽.png

这个输出同老式写法在v2.6.0版本后的输出一样,除了一开始$slots里面没有值,是后面塞进去的。

3. 多次调用同一个具名插槽

HTML

<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" v-bind:header="'header'"></slot>
        <slot>默认分发处</slot>
        <slot name="footer" v-bind:header="'footer'"></slot>
    </div>
</template>

Console输出


v2.6.10 多次使用具名插槽

从输出可以看出,新式写法多次调用同一个具名插槽,后面的会覆盖前面的,这个和老是写法一个比较大的区别,在升级的时候就要特别注意。

小结

经过上面的实践对比,有以下几点结论:

  1. v2.6.0以后在$slots里可以取到具名key,在$scopedSlots都能取到;
  2. v2.6.0以后v-slot的写法不能多次使用同名的具名插槽,后面的会覆盖前面的,不会显示两个同名具名插槽的内容;
  3. v2.6.0以后用v-slot的写法,如果在子组件中用$slot,一定调用watch方法,因为一开始$slots为空,后面才塞入的数据。
上一篇下一篇

猜你喜欢

热点阅读