vue 插槽 slot

个人理解

  • 个人感觉,为同一组件在不同的情况添加不同的内容,不需要专门修改组件,就像 java 的多态,来提高复用性。比如: 就像一块基础设施完备的土地,给你划分好区域,只要这个位置没有归属权(name),房子随便盖。
  • 我们可以理解 slot 为占住当前的位置,方便我们插入内容。
  • Vue 的插槽分为匿名插槽(单个插槽/默认插槽)、具名插槽、作用域插槽(带数据的插槽)

    • vue 在 2.6.0 中,具名插槽和作用域插槽引入了一个新的统一的语法 (即 v-slot 指令)。它取代了 slot 和 slot-scope 这两个目前已被废弃但未被移除且仍有用的特性。但是将会在vue 3 中,被废弃的这两个,不会被支持即无效且不会出现在 Vue 3 中。

      // 这是 home 组件模板
      <template>
          <div class='home'>
            <p>我是home 组件</p>
            <slot>
              <h3>没传内容</h3>
            </slot>
          </div>
        </template>
      
      //home 组件的内部内容
      <home>这是组件的内部内容</home>

slot 注意点

  1. vue 插槽的编译作用域的规则: 父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。(个人理解: 各自管各自的,谁也别干预谁。也是用 props 和 $emit 传递数据的原因之一吧。)
  2. 组件模板中 没用 slot ,那组件内部 的内容 是不会被渲染的,直接抛弃。

    <home>
      <span>{{msg}}</span>  //  报错,Property or method "msg" is not defined on the instance but referenced during render
      // 组件内部的数据,不是组件的,是其 父元素节点的Property or method。父元素节点没有声明,肯定报错。
    
      <p>是否能渲染</p>
    </home>
    
    // home 组件内部的内容全部会被抛弃,只渲染 home 的模板。等同于下面
    <home></home>
  3. 插槽用 <slot> 标签来确定渲染的位置,只能用一个默认插槽。组件内部所有的HTML内容都会被渲染到 slot 的位置。除了 template 标签绑定了 v-slot 指令 的内容
  4. v-slot 指令, 它取代了 slot 和 slot-scope。
  5. v-slot 简写把参数之前的所有内容 v-slot: 替换为字符 #。例如 v-slot:header 可以被重写为 #header

    //具名
    <template slot="header"> 
    <template #header">    <!-- <template v-slot:header"> -->
    
    // 作用域
    <template slot-scope="todo"> 
    <template v-slot="todo"> 
    
    // 具名-作用域
    <template slot-scope="todo" slot='header'> 
    <template #header="todo"> 
  6. v-slot属性只能在<template> 上使用。

后备内容 和 匿名插槽(单个插槽/默认插槽)

后备内容

当组件内部没有内容时,组件模板中的slot标签的内容会被渲染。有则渲染组件内部的内容。

  // home 组件模板
  <template>
    <div class='home'>
      <p>我是home 组件</p>
      <slot>
        <h3>没传内容</h3>
      </slot>
    </div>
  </template>

 // 组件内部
  <h2>组件内没有内容:</h2>
  <home></home>

  <h2>组件内有内容:</h2>
  <home> 
    <h3>我有内容了</h3>
  </home>


// 渲染结果
  <h2>组件内没有内容:</h2> 
    <div class="home">
      <p>我是home 组件</p> 
      <h3>没传内容</h3>
    </div> 

  <h2>组件内有内容:</h2>
    <div class="home">
      <p>我是home 组件</p>
      <h3>我有内容了</h3>
  </div> 

单个插槽( 匿名插槽/默认插槽)

  1. 单个插槽一般都是匿名的,无name属性。
注意: 组件模板中使用多个 slot 标签占位后,在组件内部的内容有多少个slot就会重复多少次。(多写几个默认插槽,怕是铁憨憨)
  // home 组件模板
  <template>
    <div class='home'>
      <p>我是home 组件</p>
      <slot>
        <h3>没传内容</h3>
      </slot>
      <slot></slot>
      <slot></slot>
    </div>
  </template>

  //组件内部
  <home>
  <p>铁憨憨</p>
  </home>

  //渲染结果
  <div class="home">
    <p>我是home 组件</p> 
    <p>铁憨憨</p>
    <p>铁憨憨</p>
    <p>铁憨憨</p>
  </div>
  1. 单个插槽当然也可以给他命名,默认未命名情况下,Vue2.6+版本默认为 v-slot:default或简写#default。也可以省略default直接写v-slot。如果写写上#default或者 v-slot,单个插槽变成了具名插槽。

    // home 组件模板
      <template>
        <div class='home'>
          <p>我是home 组件</p>
          <slot>         <!-- slot的name=default 写不写都一样 -->
            <h3>没传内容</h3>
          </slot>
        </div>
      </template>
    //
    <home >
        <p>我是 slot </p>
        <template v-slot>
          <p>我变成具名插槽了</p>
        </template>
    </home>
// 渲染结果
<div class="home">
  <p>我是home 组件</p> 
  <p>我变成具名插槽了</p>
</div>
```

具名插槽

  • 匿名插槽没有name属性,所以是匿名插槽,那么,插槽加了name属性,就变成了具名插槽。具名插槽可以有N个。但是 name 和 v-slot:'插槽名' 是一一对应的。
  • 具名的作用,也就是指向到那个位置展示。也和在组件内部的书写顺序无关。
  • 在向具名插槽提供内容的时候,我们要在一个 <template> 标签上使用 v-slot 指令,并以 v-slot 的参数的形式提供其名称。
//home组件
<div class='home'>
  <p>我是home 组件</p>

  <slot name=header></slot>
  <slot name='bar'></slot>
</div>

//内部
<homse >
  <p>我是 default </p>
  <template v-slot:header>
    <p>v-slot:header 我变成具名插槽了</p>
  </template>
  <template #bar>
    <p>#header 我变成具名插槽了</p>
  </template>
</homes>

//渲染结果
<div class="home">
  <p>我是home 组件</p> 
  <p>v-slot:header 我变成具名插槽了</p> 
  <p>#bar 我变成具名插槽了</p>
</div>

作用域插槽(带数据的插槽)

  • 其实就是获取父组件的内部数据。不用像父子组件通信一样的麻烦。
  • 绑定在 <slot> 元素上的 属性 被称为插槽 prop。现在在父级作用域中,我们可以使用带值的 v-slot 来定义我们提供的插槽 prop 的名字(注意: v-slot 定义的名字 可以和 prop 的名字不同,但是结构的时候需要重命名 prop) 。并且 slot 标签上返回的属性值,是以一个对象的形式保存起来。

      <template v-slot='res'>
        <h2>在 slot 上面绑定属性,得到父组件的数据,通过v-slot获取</h2>
        <h4>{{res}}</h4>
      </template>
       
      //
      <p>我是home 组件</p> 
      <h2>在 slot 上面绑定属性,得到父组件的数据,通过v-slot获取</h2> 
      <h4>
      {
        "res": {
          "name": "作用域插槽",
          "type": "Object"
        }
      }
      </h4>
  • 默认插槽 携带数据,会被当作具名插槽使用,slot 的 name 默认为 default。只会渲染 最后一个 <template #default='res'> 标签。
  • 具名插槽带数据,v-slot:bar='res' 简写为 #bar='res'

    <template >
      <h2>得到数据</h2>
      <h4>{{res}}</h4>
    </template>
    <template #bar='res'>
      <h2>具名插槽得到数据</h2>
      <h4>{{res}}</h4>
    </template>
    
    //
    <h2>具名插槽得到数据</h2>
    <h4>
    {
      "res": {
        "name": "作用域插槽",
        "type": "Object"
      }
    }
    </h4> 
  • 解构Prop,由于返回的是一个对象,那就可以解构。可以使接受的数据变得更简洁。

    <template #prop='{res}'>
      <h2>解构插槽 Prop</h2>
      <h4>{{res}}</h4>
    </template>
    
    //
    <h2>解构插槽 Prop</h2>
    <h4>
    {
      "name": "作用域插槽",
      "type": "Object"
    }
    </h4>
  • 尤其是在该插槽提供了多个 prop 的时候。它同样开启了 prop 重命名等其它可能,例如将 user 重命名为 person:v-slot={"user": person} 。其实就是解构Prop。

    <template #other='{"res": other}'>
      <h2>prop 重命名 </h2>
      <h4>{{other}}</h4>
    </template>
    
    //
    <h2>prop 重命名 </h2> 
    <h4>
    {
      "name": "作用域插槽",
      "type": "Object"
    }
    </h4>
  • 你甚至可以定义后备内容,用于插槽 prop 是 undefined 的情形。

    <template #uf='{uf = {arr:[1]}}'>
      <h2>用于插槽 prop 是 undefined 的情形:</h2>
      <h4>{{uf}}</h4>
    </template>
    
    //
    <h2>prop 重命名1 </h2> 
    <h4>
    {
      "arr": [
          1
      ]
    }
    </h4>
  • 当被提供的内容只有默认插槽时,组件的标签才可以被当作插槽的模板来使用。这样我们就可以把 v-slot 直接用在组件上。

    <home v-slot='{res}'>
    {{res.name}}
    </home>
  • 代码
<tempalte>
  <div class='home'>
    <p>我是home 组件</p>
    <slot :res=res ></slot>
    <slot :res=res name=bar></slot>
    <slot :res=res name=prop></slot>
    <slot :res=res name=other></slot>
    <slot :uf=uf name=uf></slot>
  </div>
</tempalte>
export default {
    name:"home",
    data() {
        return {
            "res":{
                "name": 作用域插槽,
                "type": "Object",
            },
            "uf": undefined,
        }
    },
}

转载及引用

官方插槽文档

对Vue插槽slot的理解

深入理解vue中的slot与slot-scope

如何理解Vue.js的组件中的slot?

Vue 插槽 & 高复用组件

[[Vue] slot详解,slot、slot-scope和v-slot](https://juejin.im/post/5cb056...


Sanbai
30 声望1 粉丝

正在学习前端的小白