VueSlot的使用和理解

33次阅读

共计 3688 个字符,预计需要花费 10 分钟才能阅读完成。

Slot

Slot=> 内容分发, 占位元素

父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。Slot 分发的内容,作用域是在父组件上

1.Vue2.6 版本前的旧特性用法

1.1 不具名 slot

父组件内使用子组件

<children>
    <p> 我是第一行 </p>
    <p> 我是第二行 </p>
</children>

子组件模板内容

<div>
    <p>template div 内容 </p> 
    <!-- <slot>slot 标签内的内容 </slot>slot 外 div 内的内容 -->
</div>

渲染过程:模板内容直接替换 childre 中的内容

<div>
    <p>template div p 内容 </p>
</div>

接上 启用 slot 后的渲染结果

<div>
    <p>template div 内容 </p>
    <p> 我是第一行 </p>
    <p> 我是第二行 </p>
    <!-- 复制被调用子组件内的内容并替换 <slot></slot> 自身 -->
    slot 外 div 内的内容 <!-- 该内容按从上到下被渲染 -->      
</div>

渲染过程:按子组件模板从上至下渲染,先将 <p>template div 内容 </p> 渲染出来,紧接着读取到 slot 标签立即复制被调用子组件内的内容并替换 <slot></slot> 自身,然后渲染子组件模版内剩余

1.2 具名 slot

父组件内使用子组件

<children>
    <p> 我是第一行 </p>
    <p> 我是第二行 </p>
    <slot> 第一个 slot</slot>
    <slot> 第二个 slot</slot>
    <h2 slot="header"> 头部在这 </h2>
    <p> 中间在这 </p>
    <div slot="footer">
        <div> 底部在这 </div>
    </div>
</children>

子组件模板内容

<div>
    <slot></slot>
    <h2 slot="header">h2 slot=header</h2><!-- 不报错,应该被认为常规元素,会被渲染到不具名 slot 区域 -->
    <slot name="header"></slot><!-- 在父组件中搜查匹配 带有名叫 "header"slot 的元素并复制替换本处元素 -->  
    <slot name="footer"></slot><!-- 在父组件中搜查匹配 带有名叫 "footer"slot 的元素并复制替换本处元素 -->  
</div>

渲染成:

<div>
    <p> 我是第一行 </p>
    <p> 我是第二行 </p> 第一个 slot 第二个 slot <p> 中间在这 </p>
    <h2 slot="header">h2 slot=header</h2>
    <h2> 头部在这 </h2>
    <div>
        <div> 底部在这 </div>
    </div>
</div>

渲染过程:读取到 slot 标签后将被调用的子组件中没有被具名插槽包裹的内容及子组件模版内的常规内容替换 slot 标签所在区域并按顺序渲染,读到具名 slot 则在被调用的子组件中查找与之 name 对应的内容复制替换对应的具名插槽并渲染

1.3 作用域插槽 slot-scope

2.6 之前 ==>slot scope=”别名”
在父组件内使用 slot-scope 并使用传入的数据
将 <span v-for=”item in aaa.shuju”>{{item}}</span> 复制替换子组件的 <slot></slot>, 并将“shuju”作为 receiveData 的新属性(类似这个意思),此时 receiveData.shuju 就等同于子组件中返回的 data 对象

<template slot-scope="receiveData">
    <div>
    <span v-for="item in receiveData.shuju">{{item}}</span>
   </div>
</template>

在子组件内设定传入的值并在 slot 上绑定需要传入的值
子组件内

模板:<div>
     <slot :shuju="data"></slot>
</div>

其他:

data:function(){
return{data:['zhangsan','lisi','wangwu','maliu','qianqi','zhouba']
          }
     }

最终渲染成:

<div>
    <h3> 这里是子组件 </h3>
    <div>
        <span>zhangsan</span><span>lisi</span><span>wangwu</span><span>maliu</span><span>qianqi</span><span>zhouba</span>
    </div>
</div>

2.Vue2.6 版本及以后的新特性用法

2.1 不具名插槽

父组件内使用子组件

<children>
    <template v-slot> <!-- 此处的 v -slot 等同于 v-slot:default-->
        <div>
            template v-slot 中的内容
        </div>
    </template>
</children>

子组件模板内

<div>
    <slot></slot>     
</div>

最终渲染成:

<div>
     <div>
        template v-slot 中的内容
     </div>
</div>

渲染过程基本一致

2.2 具名插槽

2.6 新特性 v-slot 只能被用于组件或者模板 上方使用 v -slot
父组件内使用子组件

<children>
    <template v-slot:header>
        hahaha
    </template>
    <template v-slot:footer>

        脚在这儿
    </template>
    <template v-slot:header> 头部在这 </template>
    <!-- 此处会覆盖上面同名 -->
    <p> 中间在这 </p>
    <template v-slot:footer>
        <!-- 此处会覆盖上面同名 -->
        <div> 底部在这 </div>
    </template>
</children>

子组件模板内

<div>
    <slot></slot>
    <slot name="header"></slot>
    <slot name="footer"></slot>
</div>

最终渲染成:

<div>
    <p> 中间在这 </p> 
    头部在这 
    <div> 底部在这 </div>
</div>

渲染过程基本一致
注意:多个同名具名插后面的覆盖前面的,只会有一个起效!

2.3 作用域插槽

v-slot
在父组件内使用 v-slot=”xxx”并传入的数据

<children>
        <template v-slot:header>
            hahaha
        </template>
        <template v-slot:footer>

            脚在这儿
        </template>
        <template v-slot:header> 头部在这 </template>
        <!-- 此处会覆盖上面同名 -->
        <p> 中间在这 </p>
        <template v-slot:footer="receiveData">
            <!-- 此处会覆盖上面同名 -->
            <div> 底部在这 </div>
            <div>{{receiveData.sendData.firstName}}+{{receiveData.sendData.lastName}}</div>
        </template>
</children>

子组件模板内

<div>
    <slot></slot>
    <slot name="header"></slot>
    <slot name="footer" :sendData="userInfo"></slot>
</div>

最终渲染成:

<div>
    <p> 中间在这 </p> 
    头部在这 
    <div> 底部在这 </div>
    <div>Brain+Lu</div>
</div>

渲染过程基本一致

3. 理解及结论

默认(后备)内容 [一般指子组件模板内的 <slot> 默认(后备)内容 </slot>] 生效的情况:在父组件内使用的子组件内不包含可渲染内容的情况下会被渲染出来。
渲染顺序:在父组中被调用的子组件外的内容有线渲染,然后子组件模板内从上至下渲染。
Slot 执行过程:子组件的模板把父组件中的内容 (<children> 内容 </children>) 选择性复制然后替换本身。
Slot- 不具名插槽 ==> 子组件模板内各个 <slot></slot> 都会把父组件中除具名插槽包裹的其他内容复制一份并替换自身 (<slot></slot>) 位置
Slot- 具名插槽 ==> 子组件模板内各个 <slot name=”xxx”></slot> 都会把父组件中的与匹配的具名插槽包裹的其他内容复制一份并替换自身(<slot></slot>) 位置再渲染
v-slot 写法同时存在多个同名具名插槽,写在最后的那个起效
同时存在两种写法的情况下 新写法的渲染优先级更高,不论是否具名都会覆盖掉就写法

<template v-slot:footer>
     template v-slot
</template>
<p slot="footer">slot=footer</p>   <!-- 此处不会被渲染,不论写在 v -slot 之前还是之后 -->

目前还未应用于实际场景,听闻 Element 的 table 组件和 Button 组件似乎有用到 slot,暂未探究,有兴趣的小伙伴可以去看看;有实际应用也可告诉我。
注:结论等均是感性认知,不一定是正确的,只是方便理解(也许只是自己)

正文完
 0