[TOC]

认识插槽Slot

  • 在开发中经常封装一个个可复用的组件:
    • 前面通过props传递给组件一些数据,让组件来进行展示;
    • 但是为了让这个组件具备更强的通用性,不能将组件中的内容限制为固定的div、span等等元素;
    • 比如某种情况下希望组件显示的是一个按钮,某种情况下希望显示的是一张图片;
    • 所以,应该让使用者可以决定某一块区域到底存放什么内容和元素;

如何使用插槽slot?

  • 定义插槽slot:
    • 插槽的使用过程其实是抽取共性、预留不同;
    • 将共同的元素、内容依然在组件内进行封装;
    • 同时会将不同的元素使用slot作为占位,让外部决定到底显示什么样的元素;
  • 如何使用slot呢?
    • Vue中将 元素作为承载分发内容的出口;
    • 在封装组件中,使用特殊的元素就可以为封装组件开启一个插槽;
    • 该插槽插入什么内容取决于父组件如何使用;

插槽的基本使用

一个组件MySlotCpn.vue:该组件中有一个插槽,我们可以在插槽中放入需要显示的内容;
我们在App.vue中使用它们:可以插入普通的内容、html元素、组件元素,都可以是可以的;

<template>
  <div>
    <test>
      我是文字~~
      <button>按钮</button>
      <!--这里是外部引入的组件-->
      <button-test></button-test>
    </test>
  </div>
</template>

<script>
  import Test from "./Test.vue";
  import ButtonTest from "./ButtonTest.vue";
  export default {
    name: "App",
    components: {
      Test,
      ButtonTest,
    },
  };
</script>
<template>
  <div>
    <h3>test</h3>
    <slot></slot>
  </div>
</template>

<script>
export default {
  name: "test",
};
</script>

这样,父组件中test标签中的全部内容,就回插入到子组件中slot的位置。

插槽的默认内容

  • 在使用插槽时,如果没有插入对应的内容,则显示一个默认的内容

    • 这个默认的内容只会在没有提供插入的内容时才会显示
      <template>
      <div>
      <test></test>
      </div>
      </template>
      
      <template>
      <div>
      <h3>test</h3>
      <slot>
       <h3>我是默认内容</h3>
      </slot>
      </div>
      </template>
      
      image.png

      多个插槽的效果

  • 如果一个组件中含有多个插槽,我们插入多个内容时是什么效果?

    • 默认情况下每个插槽都会获取到我们插入的内容来显示;

image.png

<template>
  <div class="bar">
    <div class="left">
      <slot></slot>
    </div>
    <div class="center">
      <slot></slot>
    </div>
    <div class="right">
      <slot></slot>
    </div>
  </div>
</template>

<style scoped>
.bar {
  display: flex;
}
.left,
.right {
  width: 100px;
  background-color: pink;
  height: 50px;
}
.center {
  flex: 1;
  background-color: hotpink;
}
</style>

具名插槽的使用

  • 我们希望达到的效果是插槽和内容对应显示,此时可以使用具名插槽:

    • 具名插槽顾名思义就是给插槽起一个名字, 元素有一个特殊的 attribute:name;
    • 一个不带 name 的slot,会带有隐含的名字 default;
      <test>
      <template v-slot:left>我是文字~~</template>
      <template v-slot:default><button>按钮</button></template>
      <template v-slot:right><button-test></button-test></template>
      </test>
      
      <template>
      <div class="bar">
      <div class="left">
       <slot name="left"></slot>
      </div>
      <div class="center">
       <slot></slot>
      </div>
      <div class="right">
       <slot name="right"></slot>
      </div>
      </div>
      </template>
      
      image.png

      动态插槽名

  • 什么是动态插槽名呢?

    • 目前我们使用的插槽名称都是固定的;
    • 比如 v-slot:left、v-slot:center等等;
    • 可以通过 v-slot:[dynamicSlotName]方式动态绑定一个名称; ```vue
``` ```vue ``` ### 具名插槽使用的时候缩写 - 具名插槽使用的时候缩写: - 跟 v-on 和 v-bind 一样,v-slot 也有缩写; - 即把参数之前的所有内容 (v-slot:) 替换为字符 #; ```vue ``` ## 渲染作用域 - 在Vue中有渲染作用域的概念: - 父级模板里的所有内容都是在父级作用域中编译的; - 子模板里的所有内容都是在子作用域中编译的; - 如何理解这句话呢?我们来看一个案例: - 在我们的案例中ChildCpn自然是可以访问自己作用域中的title内容的; - 但是在App中,是访问不了ChildCpn中的内容的,因为它们是跨作用域的访问; ![image.png](https://cdn.nlark.com/yuque/0/2022/png/439030/1648889318163-868fac3b-e08e-46f8-b396-e3f680fc787a.png#clientId=uf8a10be5-0a52-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=343&id=uf50b5f5f&margin=%5Bobject%20Object%5D&name=image.png&originHeight=1280&originWidth=2982&originalType=binary&ratio=1&rotation=0&showTitle=false&size=3747021&status=done&style=none&taskId=ufcac1781-1a26-45a1-8f4f-3b4b8be9a48&title=&width=800) ## 作用域插槽 - 有时候插槽访问到子组件中的内容是非常重要的: - 当一个组件被用来渲染一个数组元素时,使用插槽并希望插槽中显示每项的内容; - 针对这个,Vue提供了作用域插槽; - 来看下面的一个案例: 1. 在App.vue中定义好数据 1. 传递给ShowNames组件中 1. ShowNames组件中遍历names数据 1. 定义插槽的prop 1. 通过v-slot:default的方式获取到slot的props 1. 使用slotProps中的item和index ```vue ``` ```vue
![image.png](https://cdn.nlark.com/yuque/0/2022/png/439030/1649238196091-fe4c1af8-7109-4639-9169-61e921465060.png#clientId=u9bf55be4-f11c-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=1240&id=ud559d8d7&margin=%5Bobject%20Object%5D&name=image.png&originHeight=1240&originWidth=2968&originalType=binary&ratio=1&rotation=0&showTitle=false&size=2022715&status=done&style=none&taskId=uad3c251f-dd3f-44b5-a38c-3ee9f523f35&title=&width=2968)

<a name="nP0AT"></a>
## 独占默认插槽的缩写
如果我们的插槽是默认插槽default,那么在使用的时候 `v-slot:default="slotProps"`可以简写为`v-slot="slotProps"`
```vue
<slot-item :list="list">
  <template v-slot="slotProps">
    <h3>{{ slotProps.names }}</h3>
    <p>{{ slotProps.age }}</p>
  </template>
</slot-item>

并且如果我们的插槽只有默认插槽时,组件的标签可以被当做插槽的模板来使用,这样,我们就可以将 v-slot 直
接用在组件上:

<slot-item :list="list" v-slot="slotProps">
  <h3>{{ slotProps.names }}</h3>
  <p>{{ slotProps.age }}</p>
</slot-item>

默认插槽和具名插槽混合

但是,如果我们有默认插槽和具名插槽,那么按照完整的template编写。否则会存在问题
image.png
当存在其他命名插槽时,默认插槽必须在自定义元素上使用“