vue2和vue3插槽使用对比

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 title</h1>
  </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 info</p>
  </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 title</h1>
  </template>

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

  <template #footer>
    <p>Here's some contact info</p>
  </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>
    
<!-- 
①注意这里的other是个变量,就是那些起名字的slot的 name属性,  
不要把它和default一样,直接v-slot:other="otherSlotProps"使用,要把other替换成slot的name属性。
②也就是说出现多个插槽时候, 用v-slot:default=“slotProps” 可以匹配那些未命名插槽, 而命名插槽就要再写一个tempalte标签,并且使用插槽的名字来匹配。
-->
</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" /> 

<template>上使用特殊的 slot attribute,可以将内容从父级传给具名插槽 (把这里提到过的 `` 组件作为示例):

<base-layout>
  <template slot="header">
    <h1>Here might be a page title</h1>
  </template>

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

  <template slot="footer">
    <p>Here's some contact info</p>
  </template>
</base-layout>

或者直接把 slot attribute 用在一个普通元素上:

<base-layout>
  <h1 slot="header">Here might be a page title</h1>

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

  <p slot="footer">Here's some contact info</p>
</base-layout>

这里其实还有一个未命名插槽,也就是默认插槽,捕获所有未被匹配的内容。

上述两个示例的 HTML 渲染结果均为:

<div class="container">
  <header>
    <h1>Here might be a page title</h1>
  </header>
  <main>
    <p>A paragraph for the main content.</p>
    <p>And another one.</p>
  </main>
  <footer>
    <p>Here's some contact info</p>
  </footer>
</div>

作用域插槽

带有 slot-scope attribute 的作用域插槽 ( 自 2.6.0 起被废弃。新推荐的语法请查阅这里。 )

<template>上使用特殊的 slot-scope attribute,可以接收传递给插槽的 prop (把这里提到过的 `` 组件作为示例):

<slot-example>
  <template slot="default" slot-scope="slotProps">
    {{ slotProps.msg }}
  </template>
</slot-example>

这里的 slot-scope 声明了被接收的 prop 对象会作为 slotProps 变量存在于 作用域中。你可以像命名 JavaScript 函数参数一样随意命名slotProps`。

这里的 slot="default" 可以被忽略为隐性写法:

<slot-example>
  <template slot-scope="slotProps">
    {{ slotProps.msg }}
  </template>
</slot-example>

slot-scope attribute 也可以直接用于非 ` 元素 (包括组件):

<slot-example>
  <span slot-scope="slotProps">
    {{ slotProps.msg }}
  </span>
</slot-example>

slot-scope 的值可以接收任何有效的可以出现在函数定义的参数位置上的 JavaScript 表达式。这意味着在支持的环境下 (单文件组件现代浏览器),你也可以在表达式中使用 ES2015 解构,如下:

<slot-example>
  <span slot-scope="{ msg }">
    {{ msg }}
  </span>
</slot-example>

使用这里描述过的 <todo-list>作为示例,与它等价的使用 slot-scope 的代码是:

<todo-list v-bind:todos="todos">
  <template slot="todo" slot-scope="{ todo }">
    <span v-if="todo.isComplete"></span>
    {{ todo.text }}
  </template>
</todo-list>
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值