1.插槽 v-slot

Vue 实现了一套内容分发的 API,将 元素作为承载分发内容的出口。

Slot 通俗的理解就是“占坑”,在组件模板中占好了位置,当使用该组件标签时候,组件标签里面的内容就会自动填坑(替换组件模板中slot位置)
并且可以作为承载分发内容的出口.

插槽(Slot)是Vue提出来的一个概念,正如名字一样,插槽用于决定将所携带的内容,插入到模板template指定的某个位置,从而使模板分块,具有模块化的特质和更大的重用性。插槽显不显示、怎样显示是由父组件来控制的,而插槽在哪里显示就由子组件来进行控制。

插槽含义:引入子组件后,在插入子组件元素中添加信息或者标签,使得子组件的指定位置插入信息或者标签

插槽有三种:默认插槽、具名插槽、作用域插槽.

插槽,其实就相当于占位符。它在组件中给你的HTML模板占了一个位置,让你来传入一些东西。插槽又分为匿名插槽、具名插槽以及作用域插槽。

没有插槽的情况下在组件标签内些一些内容是不起任何作用的,当我在组件中声明了slot元素后,在组件元素内写的内容就会跑到它这里了!

插槽是父组件与子组件新的通讯的方式,可以将父组件里面的内容显示到子组件中(包括标签)

2.内容插槽

创建product.vue组件,然后引入productDetail.vue组件

<template>
  <div>
    <h3>product.vue组件</h3>
  <productDetail>hello productDetail </productDetail>
  </div>
</template>
<script setup>
 import productDetail from "./produceDetail"
</script>

productDetail.vue组件

<template>
  <div>
    <h3>productDetail.vue组件</h3>
    <slot></slot>
  </div>
</template>

当组件渲染的时候,<slot></slot>会被替换为hello productDetail

插槽内也可以包含任何模板代码,包括HTML

<productDetail>
    <h3>hello productDetail</h3>
 </productDetail>

如果<productDetail>中没有包含一个<slot>元素,则该组件起始标签和结束标签之间的任何内容都会被抛弃。

在插槽中使用数据

插槽跟模板其他地方一样都可以访问相同的实例属性而不能访问<productDetail>的作用域

<template >
  <div>
    <h3>product.vue组件</h3>
  <productDetail>
        <!-- 可以访问到product的数据 -->
    <h3>hello productDetail--{{count}}</h3>
  </productDetail>
  </div>
</template>
<script setup>
import {ref} from "vue"
 import productDetail from "./produceDetail"
const count=ref(100)
</script>

规则:
父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。

3.默认插槽 (匿名)

没有对应的名称,自动添加内容,若没有对应的,则不显示 . 匿名插槽,我们又可以叫它单个插槽或者默认插槽。与具名插槽相对,
它不需要设置name属性。(它隐藏的name属性为default。)

    语法:v-bind:自定义数据名字="子组件中的数据" 
    绑定在 元素上的特性(v-bind:list=“user”)被称为插槽 prop。现在在父级作用域中,我们可以使用带值的 v-slot 来定义我们提供的插槽 prop 的名字。

    语法:v-slot:default

有时候我们需要给插槽设置一个具体的默认内容,当别的组件没有给你内容的时候,那么默认的内容就会被渲染

<template>
  <div>
    <h3>productDetail.vue组件</h3>
    <!-- 在slot插槽里设置默认内容 hello -->
    <slot>hello</slot>
  </div>
</template>

在product组件中直接使用,默认内容 hello将会被渲染

<productDetail></productDetail>

假如既有传入的内容又有默认内容,那么这个传入的内容将会替代默认的内容被渲染出来.

当然默认插槽有一个统一的名字叫做default,我们可以通过参数的方式指定名字

<productDetail>
    <template v-slot:default>
       <h3>hello productDetail--{{count}}</h3>
    </template>
</productDetail>

4.具名插槽

有时候我们一个组件里需要多个插槽

对于这样的情况,<slot>元素有一个特殊的特性:name ,这个特性可以用来定义额外的插槽

插槽有一个name属性。与匿名插槽相对,加了name属性的匿名插槽就是具名插槽。
组件通过在template上写v-slot:name来使用具名插槽
注意 v-slot 只能添加在template标签上
    父组件中 使用子组件标签时用的v-slot:name
    要跟子组件的name匹配上,才会渲染出来
  需要template

productDetail组件:

<template lang="">
  <div>
    <h3>productDetail.vue组件</h3>
    <!-- 在slot插槽里设置默认内容 hello -->
    <!-- <slot>hello</slot> -->
    <slot name="title"></slot>
    <slot name="price"></slot>
  </div>
</template>

product.vue组件

<productDetail>
   <template v-slot:title>
     <h3>OPPO Reno6 Pro+ 12+256GB</h3>
   </template>
   <template v-slot:price>
     <h3>¥ 3499.00</h3>
   </template>
  </productDetail>

如果一个<slot>不带name属性的话,那么它的name默认为default

注:v-slot只能添加在一个<template>

v-onv-bind 一样,v-slot 也有缩写,即把参数之前的所有内容 (v-slot:) 替换为字符 #

注:该指令和其他指令一样,只在其有参数的时候才可用

<productDetail>
  <template #title>
     <h3>OPPO Reno6 Pro+ 12+256GB</h3>
   </template>
   <template #price>
     <h3>¥ 3499.00</h3>
   </template>
</productDetail>

5.作用域插槽

其实就是可以传递数据的插槽。子组件中的一些数据想在父组件中使用,必须通过规定的方法来传递。在官方文档中提出了一条规则,父级模板里的所有内容都是在父级作用域中编译的。子模板里的所有内容都是在子作用域中编译的。插槽跟模板其他地方一样都可以访问相同的实例属性(也就是相同的”作用域”),而不能访问<productDetail>的作用域

那如果想访问<test>作用域该怎么办呢?
我们把需要传递的内容绑到 <slot> 上,然后在父组件中用v-slot设置一个值来定义我们提供插槽的名字

productDetail.vue组件:

<template>
  <div>
    <h3>productDetail.vue组件</h3>
    <slot name="student"  :student="people"  ></slot>
    <slot name="goods"    :goods="goodsList" ></slot>

  </div>
</template>
<script setup>
import {ref,reactive} from "vue"
  const id=ref("110934");
   const {people,goodsList}=reactive({
      people:{
        name:'lucky',
        age:12
      },
      goodsList:[
        {
          id:1102,
          name:'戴尔(DELL)游匣G15 15.6英寸',
          price:'¥ 5199.00'
        },
        {
          id:'1106',
          name:'美的(Midea)S8+自动集尘扫拖机器人',
          price:'¥ 2499.00'
        },
        {
          id:'11056',
          name:'Apple Watch SE',
          price:'¥ 2119.00'
        }
      ]
   })
</script>
<style lang="scss">

</style>

product.vue组件:

 <productDetail>
    <template #student="studentDetail">
     {{studentDetail}}
     <p>
       当前学生的名字是:{{studentDetail.student.name}},
       当前学生的姓名是:{{studentDetail.student.age}}
     </p>
   </template>
  </productDetail>

6.解构插槽Prop

因为 作用域插槽 的内部工作原理是将你的插槽内容包括在一个传入单个参数的函数里
这意味着 v-slot 的值实际上可以是任何能够作为函数定义中的参数的 JS 表达式

 <productDetail>
     <template #student={student}>
     {{student}}
     <p>
       当前学生的名字是:{{student.name}},
       当前学生的姓名是:{{student.age}}
     </p>
   </template>
 </productDetail>

这样可以使模板更简洁,尤其是在该插槽提供了多个 prop 的时候。它同样开启了 prop 重命名等其它可能.

 <productDetail>
     <template #student={student:studentDetail}>
     {{studentDetail}}
     <p>
       当前学生的名字是:{{studentDetail.name}},
       当前学生的姓名是:{{studentDetail.age}}
     </p>
   </template>
 </productDetail>
文档更新时间: 2023-01-02 15:15   作者:董老师