插槽是什么

插槽就是Vue实现的一套内容分发的API,这套 API的设计灵感源自 Web Components规范草案,将<slot></slot>元素作为承载分发内容的出口。

默认情况下,我们的组件是没有插槽的,这时候我们在组件标签内写入UI组件是不起任何作用的,当我在组件中声明了slot元素后,在组件元素内写的内容就能写入到指定的插槽中了。

通俗理解就是组件内部预留一个或多个的插槽位置,在编写组件时,可通过插槽名称传入其他UI组件。插槽的出现,让组件变的更加灵活。

编译作用域

编译过程就是对预处理完的文件进行一系列的词法分析,语法分析,语义分析及优化后生成相应的汇编代码。那么这里的编译作用域,可以理解为插槽slot在未运行时的它的作用域。

官方给出的一条规则:

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

有点难以理解,我们来看个示例(忽略其他代码,仅看<slot-demo>组件的内容):

<template>
  <div class="hello">
    <el-tabs :tab-position="tabPosition">
      <el-tab-pane label="插槽示例">
      // 这里的 slot-demo 是能使用 当前父组件的data数据 tabPosition
        <slot-demo msg="设置msg的值"> {{ tabPosition }} </slot-demo>
     // 但是我们想直接在这里的 slot-demo 获取到 msg 的值是获取不到的, 如下面的代码:
     // <slot-demo msg="设置msg的值"> {{ msg }} </slot-demo>
      </el-tab-pane>
    </el-tabs>
  </div>
</template>

<script>
import SlotDemo from "./slot-demo";
export default {
  name: "HelloWorld",
  components: {
    SlotDemo,
  },
  data() {
    return {
      tabPosition: "left",
    };
  },
};
</script>

所以说上面定义的规则可以简单理解为,父组件的数据可以在子组件的slot里面使用,但是子组件的数据是没法直接在当前slot中使用。但是有时候我们又需要在当前组件的slot里面使用子组件的数据,那么可以用后面介绍的作用域插槽的方式实现。

作用域插槽

在线示例
我们在<current-user>组件中定义slot插槽,

<template>
  <div class="container">
    <span>
      <slot v-bind:user="userInfo">{{ userInfo.lastName }}</slot>
      <slot v-bind:user2="userInfo" name="last"></slot>
      <slot v-bind:user1="userInfo" name="middle"></slot>
    </span>
  </div>
</template>

<script>
export default {
  name: "CurrentUser",
  data() {
    return {
      userInfo: {
        firstName: "Fan",
        middleName: "hhh",
        lastName: "Jun",
      },
    };
  },
  methods: {},
};
</script>

<style scoped>
.container {
  display: flex;
  flex-direction: column;
}
</style>

并用data中的user对象的lastName属性的值做默认内容,
然后我们在<slot-demo>组件中取得<current-user>组件中的data值,并替换掉slot的默认值。

伪代码如下:

<span>作用域插槽-独占默认插槽的缩写语法</span>
    <current-user v-slot:default="slotProps">
      {{ slotProps.user.firstName }}
    </current-user>
    <span>作用域插槽-有多个插槽时</span>
    <current-user>
      <template v-slot:default=""> 你好 </template>
      <template v-slot:last="userData">
        {{ userData.user2.firstName }}
      </template>
      <template v-slot:middle="userData1">
        {{ userData1.user1.middleName }}
      </template>
    </current-user>

效果如下:
在这里插入图片描述

注意默认插槽的缩写语法不能和具名插槽混用,因为它会导致作用域不明确
只要出现多个插槽,请始终为所有的插槽使用完整的基于 的语法:

作用域插槽的内部工作原理是将你的插槽内容包裹在一个拥有单个参数的函数里:

function (slotProps) {
  // 插槽内容
}

这意味着 v-slot的值实际上可以是任何能够作为函数定义中的参数的JavaScript 表达式
如下面的伪代码,

 <current-user>
      <template v-slot:middle="userData1">
        {{ userData1.user1.middleName }}
      </template>
    </current-user>

等价于这段代码

 <current-user>
      <template v-slot="{ user1 }"> {{ user1.middleName }} </template>
    </current-user>

插槽<slot>是可以预留多个的,那么为了区分不同的插槽,我们通过具名插槽来实现。

具名插槽

下面是个具名插槽的示例, 在线例子可点击查看

 <base-layout>
      <template #header>
        <h1>Here might be a page title</h1>
      </template>

      <template v-slot:footer>
        <p>Here's some contact info</p>
      </template>

      <p>A paragraph for the main content.</p>
      <p>And another one.</p>
    </base-layout>

具名插槽的使用限制:

  1. 具名插槽的内容必须使用模板 包裹;
  2. 具名插槽名称可以使用v-slot:名称或者使用缩写#名称
  3. 未指定名字的模板 默认插入名称为default的插槽中

官方给出的建议:

只要出现多个插槽,请始终为所有的插槽使用完整的基于 的语法

后备内容(插槽的默认值)

插槽的后备内容可以理解为插槽内容的默认值,它只会在插槽没有提供内容的时候被渲染。

如我们定义了<submit-button>,大部分情况下默认文本是显示Submit,而有时候我们会显示Save,这时候我们就可以在<submit-button>的组件中定义slot的默认内容为Submit即可。

在线示例

有时候我们可能需要动态修改插槽名称,那么怎么实现呢?
利用动态插槽名实现。

动态插槽名

首先我们定义了一个slot,主要看最后一个v-bind:user3="userInfo" name="final"

伪代码如下:

<template>
  <div class="container">
    <span>
      <slot v-bind:user="userInfo">{{ userInfo.lastName }}</slot>
      <slot v-bind:user2="userInfo" name="last"></slot>
      <slot v-bind:user1="userInfo" name="middle"></slot>
      <slot v-bind:user3="userInfo" name="final"></slot>
    </span>
  </div>
</template>

<script>
export default {
  name: "CurrentUser",
  data() {
    return {
      userInfo: {
        firstName: "Fan",
        middleName: "hhh",
        finalName: "hehehe",
        lastName: "Jun",
      },
    };
  },
  methods: {},
};
</script>

<style scoped>
.container {
  display: flex;
  flex-direction: column;
}
</style>

然后我们在slot-demo组件中使用

<template>
  <div class="solt-container">
<span>动态插槽</span>
    <current-user>
      <template v-slot:default=""> 你好 </template>
      <template v-slot:[dynamicSlotName]="userData1">
        {{ userData1.user1.finalName }}
      </template>
    </current-user>
      </div>
</template>

<script>
import CurrentUser from "./current-user";
export default {
  name: "SlotDemo",
  components: {

    CurrentUser,
  },

  data() {
    return {
      dynamicSlotName: "final",
    };
  },
  methods: {},
};
</script>

slot中的名字dynamicSlotNamedata动态传递给v-slot的,故而实现动态插槽。

在线示例

在线示例

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐