一、定义:

基础定义

如果被引用的子组件里面包含 <slot></slot> ,那么当它实际被使用的时候,<slot></slot>会被替换成使用时开始标签和结束标签之间的值。

  1. <!-- 父组件 -->
  2. <navigation-link url="/profile">
  3. Your Profile
  4. </navigation-link>
  5. <!-- 子组件 -->
  6. <a v-bind:href="url" class="nav-link">
  7. <slot></slot>
  8. </a>

默认值

子组件在 <slot></slot> 标签内部写值,则为默认值,会在父组件无传值时使用。

  1. <!-- 子组件 -->
  2. <a v-bind:href="url" class="nav-link">
  3. <slot>我是默认值</slot>
  4. </a>
  5. <!-- 父组件 -->
  6. <navigation-link url="/profile">
  7. 我是更新后的值
  8. </navigation-link>

具名插槽

父组件中 v-slot:name 包裹元素,子组件使用 <slot name="name"></slot> 接收元素,就可以把父组件中的特定元素传送到子组件的特定部分。

如果没有用 v-slot:name 包裹,那么会默认name为 default,同理子组件中的slot的name属性也是 default

  1. <!-- 子组件 -->
  2. <div id="TestSlot">
  3. <slot name="one" />
  4. <slot name="two" />
  5. </div>
  6. <!-- 父组件 -->
  7. <test-slot>
  8. <template v-slot:two>
  9. <div>我是第二个插槽</div>
  10. </template>
  11. <template v-slot:one>
  12. <div>我是第一个插槽</div>
  13. </template>
  14. </test-slot>
  15. <!-- 渲染结果 -->
  16. <div data-v-725483ce="" data-v-15737ea2="" id="TestSlot">
  17. <div data-v-15737ea2="" data-v-725483ce="">我是第一个插槽</div>
  18. <div data-v-15737ea2="" data-v-725483ce="">我是第二个插槽</div>
  19. </div>

具名插槽的缩写(>2.6.0)

v-slot:top 可以被缩写为 #top,该语法在名字为空时无效,至少要使用#default

作用域插槽

在vue的组件中,父组件不能访问子组件中的数据。

  1. <!-- 子组件 -->
  2. <template>
  3. <div>
  4. <slot name="top" :myUser="user">{{user.currentName}}</slot>
  5. </div>
  6. </template>
  7. <script>
  8. export default {
  9. name: "TestSlot",
  10. data: function () {
  11. return {
  12. user: {currentName: "Ross", lastName: 'Foo'}
  13. }
  14. }
  15. }
  16. </script>
  17. <!-- 父组件 -->
  18. <test-slot v-slot:top>{{user.lastName}}</test-slot>
  19. <!-- 报错 -->

如果想要父组件访问子组件中的数据,只需要加上scope的传值,就可以拿到在slot上传入的所有属性:

  1. <!-- 子组件 -->
  2. <template>
  3. <div>
  4. <slot name="top" :myUser="user" :testUser="'testUser'"></slot>
  5. </div>
  6. </template>
  7. <script>
  8. export default {
  9. name: "TestSlot",
  10. data: function () {
  11. return {
  12. user: {currentName: "Ross", lastName: 'Foo'}
  13. }
  14. }
  15. }
  16. </script>
  17. <!-- 父组件 -->
  18. <test-slot v-slot:top="scope">{{scope}}</test-slot>
  19. <!-- { "myUser": { "currentName": "Ross", "lastName": "Foo" }, "testUser": "testUser" } -->

与解构赋值结合
  1. // 与上例结合
  2. <!-- 父组件 -->
  3. <test-slot v-slot:top="{myUser}">{{myUser}}</test-slot>
  4. <!-- { "currentName": "Ross", "lastName": "Foo" } -->

「已废弃」作用域插槽slot-scope和slot

注意!与 v-slot 相比,slot-scope 必须要在组件使用的内部新建一个节点,<template> 或者 <div>都可以。

官方文档是这么写的,应该是单指的默认值插槽的使用,毕竟具名插槽还是要在父组件里新增节点。

  1. <test-slot>
  2. <template slot="top" slot-scope="slotProps">
  3. {{slotProps}}
  4. </template>
  5. </test-slot>

二、为什么要用

如果单纯使用 $emitprops 进行父子组件的交互,例如 根据子组件中某个交互决定整体组件显隐性的变化这样的需求,就需要冗杂至少一个方法一个变量。

官网的例子就很直接:

  1. <todo-list v-bind:todos="todos">
  2. <template v-slot:todo="{ todo }">
  3. <span v-if="todo.isComplete"></span>
  4. {{ todo.text }}
  5. </template>
  6. </todo-list>

20.05.27 updated

  • 🤔在这种场景下,使用slot似乎不如.sync