vue2和vue3插槽使用对比

文章目录

    • vue3
      • 具名插槽
        • 一个不带 `name` 的 slot 出口会带有隐含的名字“default”。
        • 具名插槽的缩写
      • 作用域插槽
      • element-plus #default="AAA"缩写形式:
        • 独占默认插槽的缩写语法
        • 解构插槽(也即独占插槽的结构插槽)
    • vue2 (2.6.0以下)
      • 具名插槽
      • 作用域插槽

vue3

具名插槽

<slot name="header" > 

对于这样的情况,`` 元素有一个特殊的 attribute:name。通过它可以为不同的插槽分配独立的 ID,也就能够以此来决定内容应该渲染到什么地方:

<div class="container">
  <header>
    <slot name="header">slot>
  header>
  <main>
    <slot>slot>
  main>
  <footer>
    <slot name="footer">slot>
  footer>
div>
一个不带 name 的 slot 出口会带有隐含的名字“default”。

在向具名插槽提供内容的时候,我们可以在一个 元素上使用v-slot指令,并以v-slot` 的参数的形式提供其名称:

<base-layout>
  <template v-slot:header>
    <h1>Here might be a page titleh1>
  template>

  <template v-slot:default>
    <p>A paragraph for the main content.p>
    <p>And another one.p>
  template>

  <template v-slot:footer>
    <p>Here's some contact infop>
  template>
base-layout>


缩写形式:

具名插槽的缩写

2.6.0 新增(也是在2.6.0开始废弃了 slot 和 slot-scope的语法的·)

v-onv-bind 一样,v-slot 也有缩写,即把参数之前的所有内容 (v-slot:) 替换为字符 #。例如 v-slot:header 可以被重写为 #header

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

  <template #default>
    <p>A paragraph for the main content.p>
    <p>And another one.p>
  template>

  <template #footer>
    <p>Here's some contact infop>
  template>
base-layout>

作用域插槽

我的理解作用域插槽是为了让子组件的数据被父组件拿到。也可以理解为让子组件给父组件传递数据。子组件给父组件传递数据用emit不就行了吗。但emit有个缺陷。就是多级(三级以及以上)组件有底层组件向上传递时候。难道要一层一层emit吗?

还有就是让中间层组件不处理业务逻辑。顶层组件处理业务逻辑,中间层组件只生成样式。

定义孙子组件:
List.vue
<template>
  <div>
    <h3>商品列表h3>
    <div>
      {{ ListData }}
    div>
  div>
template>

<script>
import { reactive, toRefs, ref } from "vue";
export default {
  props: {
    ListData: Object,
  },
  setup() {
    const clickModify = (item) => {
      console.log(item);
    };
    return { clickModify };
  },
};
script>

父组件:
AboutChild.vue
<template>
  <div>
    <div class="for">
      <h3 v-for="(item, index) in column" :key="index">
        <slot :item="item">slot>
      h3>
    div>
  div>
template>

<script>
import { reactive, toRefs, refs } from "vue";
export default {
  props: {
    column: Object,
  },
  setup() {
    const hobbies = [
      { name: "a", age: 12 },
      { name: "b", age: "123" },
      { name: "ccc", age: 123 },
      {},
    ];
    const data = reactive({ hobbies });
    return { ...toRefs(data) };
  },
};
script>

爷爷组件:
AbouView.vue

<template>
  <div>
    <AboutChild
      v-for="item in columns"
      :key="item.name"
      :column="item.childrenList"
    >
      <template #default="AAA">
        <List :ListData="AAA.item" />
      template>
    AboutChild>
  div>
template>

<script>
import { reactive, toRefs, ref } from "vue";
import AboutChild from "./children/AboutChild";
import List from "./children/children/List";
export default {
  components: { AboutChild, List },
  setup() {
    let name = ref("name");

    let data = reactive({
      columns: [
        {
          name: "好购物",
          childrenList: [
            {
              title: "a",
            },
            {
              title: "b",
            },
            {
              title: "c",
            },
            {
              title: "e",
            },
          ],
        },
        {
          name: "新青年",
          childrenList: [
            {
              title: "A",
            },
            {
              title: "B",
            },
            {
              title: "C",
            },
            {
              title: "D",
            },
          ],
        },
      ],
    });
    return {
      name,
      ...toRefs(data),
    };
  },
};
script>


把爷爷组件里的内容拎出来:

    <AboutChild
      v-for="item in columns"
      :key="item.name"
      :column="item.childrenList"
    >
      <template v-slot:default="AAA">
        <List :ListData="AAA.item" />
      template>
    AboutChild>



element-plus #default="AAA"缩写形式:

 v-slot:default="AAA" -----> #default="AAA"(element-plus中用了大量的这种缩写)
为啥v-slot后面跟的是 default呢? ====> 因为slot如果没有name属性的话, v-slot:default 匹配这些没有命名的slot;  有名字的话要 v-slot:名字 ="AAA" 来匹配
也就是说我如果 是 <slot name="yazhou" :item="item"> </slot>  那我就要写  v-slot:yazhou="AAA"
独占默认插槽的缩写语法

在上述情况下,当被提供的内容只有默认插槽时,组件的标签才可以被当作插槽的模板来使用。这样我们就可以把 v-slot 直接用在组件上:

<todo-list v-slot:default="slotProps">
  <i class="fas fa-check">i>
  <span class="green">{{ slotProps.item }}span>
todo-list>

这种写法还可以更简单。就像假定未指明的内容对应默认插槽一样,不带参数的 v-slot 被假定对应默认插槽:

<todo-list v-slot="slotProps">
  <i class="fas fa-check">i>
  <span class="green">{{ slotProps.item }}span>
todo-list>

注意默认插槽的缩写语法不能和具名插槽混用,因为它会导致作用域不明确:

!-- 无效,会导致警告 -->
<todo-list v-slot="slotProps">
  <i class="fas fa-check">i>
  <span class="green">{{ slotProps.item }}span>
  
  <template v-slot:other="otherSlotProps">
    slotProps 在此处不可用
  template>
todo-list>

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

<todo-list>
  <template v-slot:default="slotProps">
    <i class="fas fa-check">i>
    <span class="green">{{ slotProps.item }}span>
  template>

  <template v-slot:other="otherSlotProps">
    ...
  template>
    

todo-list>
解构插槽(也即独占插槽的结构插槽)

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

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

这意味着 v-slot 的值实际上可以是任何能够作为函数定义中的参数的 JavaScript 表达式。所以在支持的环境下 (单文件组件或现代浏览器),你也可以使用 ES2015 解构来传入具体的插槽 prop,如下:

<current-user v-slot="{ user }">
  {{ user.firstName }}
current-user>

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

<current-user v-slot="{ user: person }">
  {{ person.firstName }}
current-user>

vue2 (2.6.0以下)

v-slot 指令自 Vue 2.6.0 起被引入,提供更好的支持 slot 和 slot-scope attribute 的 API 替代方案。v-slot 完整的由来参见这份 RFC。在接下来所有的 2.x 版本中 slot 和 slot-scope attribute 仍会被支持,但已经被官方废弃且不会出现在 Vue 3 中。

在 2.6.0 中,我们为具名插槽和作用域插槽引入了一个新的统一的语法 (即 v-slot 指令)。它取代了 slotslot-scope 这两个目前已被废弃但未被移除且仍在文档中的 attribute。新语法的由来可查阅这份 RFC。

具名插槽

<slot name="header" />