vue slot (插槽)

148 阅读2分钟

前提

在应用子组件时,是不可以包着其他内容的 🌰:

<father>
  <child></child>
</father>

但是,有时需要自定义一些标签,或者添加一些内容。就形成了插槽

插槽的定义

slot(插槽):是组件的一块HTML模板,接受父组件传过来的插槽内容,生成Vnode并返回的函数。

插槽的分类

  • 匿名插槽 也叫单个插槽或默认插槽。不需要设置name属性,它隐藏的name属性是default
<!-- 封装的组件 child组件 -->
<template>
 <div class="child>
   <h1>子组件:匿名插槽</h1>
   <slot></slot>
  </div>
</template>

<!-- 组件调用页面 -->
<template>
 <div class="parent">
  <child>
  <template>
   <p>插入匿名插槽</p>
   </template>
   <child>
  </div>
</template>

image.png

  • 具名插槽 需要设置name属性
<!-- 封装的组件 child组件 -->
<template>
 <div class="child">
   <h1>子组件:具名插槽</h1>
   <slot name="child"></slot>
  </div>
</template>

<!-- 组件调用页面 -->
<template>
 <div class="parent">
  <child>
       <template v-slot:child>//另外一种写法:<template #child>
        <p>插入具名插槽</p>
       </template>
   <child>
  </div>
</template>

image.png

  • 作用域插槽 封装的组件要给插入的组件传值
<!-- 封装的组件 -->
<template>  
    <div class="child">    
       <h3>child组件标题</h3>    
       <slot :data="list"></slot>  
    </div> 
</template>
data(){
  return {
    list:[1,2,3,4,5]
  }
}

<!-- 组件调用页面-->
<template>
 <div class="parent">
  <child>
       <template slot-scope="childData"> // vue2中的写法
       <template v-slot="childData"> // vue2中的写法
       <div v-for="(item,index) in childData.data">
          {{item}}
       </div>
        
       </template>
   <child>
  </div>
</template>

跨组件传递slot

  • 第一种:嵌套传递
  • 第二种:Render函数,通过$slots访问当前组件的slot元素,实现传递

vue2、vue3的区别

具名插槽
// vue3的写法
<div>
  <Child>
    <template v-slot:title>
      <p>title的插槽</p>
    </template>
  </Child>
</div>

// Child组件
<div>
  <p>
    <slot name="title"></slot>
  </p>
</div>
// vue2的写法
<div>
  <Child>
      <p slot="title">title的插槽</p>
   
  </Child>
</div>

// Child组件
<div>
  <p>
    <slot name="title"></slot>
  </p>
</div>

区别:

  • vue3在父组件使用具名插槽时用的是v-slot,vue2使用slot
  • vu3必须把v-slot写在template标签中,而vue2中slot可以写在任意标签中
作用域插槽
// vue3的写法
<div>
  <Child>
    <template v-slot:title="{data}">
      <p>title的插槽:{{data}}</p>
    </template>
  </Child>
</div>

// Child组件
<div>
  <p>
    <slot name="title" :data="title"></slot>
  </p>
</div>
// vue2的写法
<div>
  <Child>
      <p slot="title" slot-scope="scope">title的插槽{{scope.data}}</p>
   
  </Child>
</div>

// Child组件
<div>
  <p>
    <slot name="title" :data="title"></slot>
  </p>
</div>
data(){
  return{
    title:'组件的值'
  }
}

区别:

  • vue3在父组件获取值直接用v-slot,vue2中则使用slot-scope

slot原理

组件渲染原理

组件的核心是:渲染函数,组件的挂载本质是执行渲染函数并得到要渲染的VNode。 组件渲染的流程是先创建组件实例,然后初始化组件实例,在初始化组件实例的时候会处理slot相关的内容

slot初始化原理
  • 源码的runtime-core\src\component.ts里
export function setupComponent(){
   ....
   initslots(instance,children)
   ....
}
  • 源码的runtime-core\src\componentSlots.ts里
// initSlots函数就是把children赋值给instance.slots
export const initSlots = ()=>{
}

vue2中slot与vue3之间的区别

vue2

父组件更新时,插槽会被重新渲染

vue3
  • 当slot的内容发生变化时,只有子组件会被重新渲染
  • 当父组件重新渲染时,如果子组件的内容未发生变动,子组件就不需要重新渲染