2.9 插槽

目录

插槽使用

默认插槽

具名插槽

作用域插槽

父组件插槽里的内容是响应式的情况解析

父组件数据变化触发重新渲染

插槽内容更新传递到子组件

子组件的更新策略

示例说明

结论

底层原理解析(如果有不正确,欢迎大佬指正)

关键机制与技术原理

插槽中的样式处理

综合案例:

子组件:CardDemo.vue

父组件:App.vue


插槽使用

插槽(Slot)是Vue为组件封装者提供的能力,允许开发者在封装组件时,将不确定的、希望由用户指定的部分定义为插槽。其核心作用是让父组件可以向子组件指定位置插入HTML结构 ,是一种组件间通信方式,适用于父组件向子组件传递内容的场景。例如,当多个组件框架结构相同但内部内容不同(如分类栏中的电影列表和风景图片)时,可通过插槽灵活定制内容

Vue 2 中,插槽(slots)是组件之间传递内容的一种方式。它们允许你在父组件中定义要插入到子组件中的内容。Vue 2 提供了三种类型的插槽:默认插槽、具名插槽和作用域插槽。

默认插槽

默认插槽是没有指定名称的插槽,通常用于当只有一个插槽出口时。以下是如何使用默认插槽的例子:

复制代码
<!-- 子组件模板 -->
<template>
  <div>
    <slot>这里是默认内容</slot>
  </div>
</template>

<!-- 父组件使用子组件 -->
<child-component>
  <span>这是通过父组件传入的内容。</span>
</child-component>

如果没有提供任何内容,将会渲染默认内容"这里是默认内容"。

具名插槽

如果你需要在同一组件中有多个插槽出口,你可以为每个插槽指定一个名字。这样你就可以有针对性地向特定的插槽传递内容:

复制代码
<!-- 子组件模板 -->
<template>
  <div>
    <header>
      <slot name="header"></slot>
    </header>
    <main>
      <slot></slot>
    </main>
    <footer>
      <slot name="footer"></slot>
    </footer>
  </div>
</template>

<!-- 父组件使用子组件 -->
<child-component>
  <template v-slot:header>
    <h1>这里会出现在头部</h1>
  </template>
  <p>这里会出现在主体部分</p>
  <template #:footer>
    <p>这里会出现在页脚</p>
  </template>
</child-component>

父组件使用slot="名称"(Vue2.6前)或v-slot:名称(Vue2.6+,简写为#名称)指定内容插入位置,推荐使用<template>标签包裹以避免多余DOM结构

v-slot 是 Vue 2.6.0 引入的指令,它取代了旧的 slot 属性。为了简化代码,可以使用 # 作为 v-slot: 的缩写。

2.6以前案例

复制代码
<!-- 子组件模板 -->
<template>
  <div>
    <header>
      <slot name="header"></slot>
    </header>
    <main>
      <slot></slot>
    </main>
    <footer>
      <slot name="footer"></slot>
    </footer>
  </div>
</template>

<!-- 父组件使用子组件 -->
<child-component>
  <template slot="header">
    <h1>这里会出现在头部</h1>
  </template>
  <p>这里会出现在主体部分</p>
  <template slot="footer">
    <p>这里会出现在页脚</p>
  </template>
</child-component>

作用域插槽

有时你可能希望从子组件向父组件传递数据。这时可以使用作用域插槽,通过插槽 prop 将数据从子组件传递给父组件:

复制代码
<!-- 子组件模板 -->
<template>
  <div>
    <slot :user="user"></slot>
  </div>
</template>

<script>
export default {
  data() {
    return {
      user: { firstName: 'John', lastName: 'Doe' }
    };
  }
};
</script>

<!-- 父组件使用子组件 -->
<child-component>
  <template v-slot:default="slotProps">
    {{ slotProps.user.firstName }} {{ slotProps.user.lastName }}
  </template>
</child-component>

在这个例子中,slotProps 包含了所有由子组件传递过来的插槽 prop,父组件可以通过解构的方式直接访问这些属性。

Vue 2.6 之前,slot-scope 是实现作用域插槽的主要方式

复制代码
<!-- 子组件模板 -->
<template>
  <div>
    <!-- 向父组件传递一个名为 'user' 的对象 -->
    <slot :user="user"></slot>
  </div>
</template>

<script>
export default {
  data() {
    return {
      user: { name: 'John Doe', age: 30 }
    };
  }
};
</script>

<!-- 父组件使用子组件 -->
<child-component>
  <!-- 使用 slot-scope 来接收从子组件传来的数据 -->
  <template slot-scope="slotProps">
    {{ slotProps.user.name }} - {{ slotProps.user.age }}
  </template>
</child-component>

父组件插槽里的内容是响应式的情况解析

父组件数据变化触发重新渲染

  • 当父组件 v-slot 中使用的响应式数据发生变化 时(如 datacomputed 属性),Vue 的响应式系统会自动触发父组件的重新渲染
  • 父组件会重新生成插槽内容(模板内容),包括作用域插槽中定义的 DOM 结构和逻辑。

插槽内容更新传递到子组件

  • 重新生成的插槽内容(含更新后的数据)会作为新的 VNode 传递给子组件
  • 子组件通过 <slot> 接收更新后的内容,并替换旧内容,实现动态插入

子组件的更新策略

  • 不触发子组件自身渲染
    若子组件内部状态未变化,仅插槽内容更新,则子组件不会触发自身重渲染(节省性能)。
  • 仅局部更新
    Vue 通过虚拟 DOM 的 diff 算法,仅更新插槽对应的 DOM 节点,而非整个子组件

示例说明

假设有一个场景,父组件包含一个响应式的计数器,该计数器用于控制作用域插槽中显示的内容:

复制代码
<!-- 子组件 -->
<template>
  <div>
    <slot :user="user"></slot>
  </div>
</template>

<script>
export default {
  data() {
    return {
      user: { name: 'John Doe' }
    };
  }
};
</script>

<!-- 父组件 -->
<template>
  <div>
    <child-component>
      <template v-slot:default="slotProps">
        {{ slotProps.user.name }} - Counter: {{ counter }}
      </template>
    </child-component>
    <button @click="increment">Increment Counter</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      counter: 0
    };
  },
  methods: {
    increment() {
      this.counter++;
    }
  }
};
</script>

在这个例子中,每当点击按钮时,counter 值增加,并且由于 counter 是响应式的,Vue 会自动更新插槽中显示的内容。注意这里虽然 counter 是父组件的数据,但其变化会导致插槽内容的更新,而无需重新渲染整个子组件。

结论

  • 当父组件 v-slot 内使用的数据是响应式的并且发生变化时,Vue 会自动重新渲染受影响的部分。
  • 插槽内容基于父组件的数据进行渲染,并通过插槽机制放置在子组件模板的指定位置。因此,更新是局部的,只影响到相关内容,而不是整个子组件。
  • 这种机制保证了高效的更新策略,使得应用性能最优。

底层原理解析(如果有不正确,欢迎大佬指正)

关键机制与技术原理

  1. 作用域插槽的本质

    • 作用域插槽实际是函数式组件
      子组件的 <slot> 会被编译为一个函数,父组件传递的插槽内容作为该函数的参数。
    • 数据流:
      子组件数据 → 通过函数参数传递 → 父组件模板渲染 → 结果插入子组件
  2. 响应式依赖追踪

    • 父组件在渲染插槽时,会自动追踪所有响应式依赖 (如 slotProps.item.text )。
    • 当依赖数据变化时,Vue 精准触发插槽内容的重新渲染。
  3. 性能优化策略

    • 静态内容提升
      若插槽中存在静态内容(如 <div>标题</div>),Vue 会跳过其重复渲染。
    • 动态内容隔离
      动态部分(如 {``{slotProps.item}} )独立更新,避免整树重渲染

插槽中的样式处理

在 Vue 中,插槽(slot)的内容是由父组件定义的,因此插槽中的样式通常遵循父组件的样式规则。这意味着父组件可以直接控制插槽内容的样式,而无需子组件特别处理。

综合案例:

假设我们有一个子组件 CardDemo.vue,它定义了一个卡片布局,并且允许父组件通过作用域插槽自定义卡片的内容。我们的目标是确保父组件传递的内容能够正确地应用样式。

子组件:CardDemo.vue
复制代码
<template>
  <div class="card">
    <header class="card-header">
      <slot name="header" >Default Header</slot>
    </header>
    <main class="card-body">
      <slot >Default Body Content</slot>
    </main>
  </div>
</template>
 
<script>
export default {
  data() {
    return {
     
    };
  }
};
</script>
 
<style scoped>
.card {
  border: 1px solid #ccc;
  border-radius: 4px;
  padding: 16px;
}
 
.card-header {
  background-color: #f7f7f7;
  padding-bottom: 8px;
  margin-bottom: 16px;
}
 
.card-body {
  color: #333;
}
</style>

在这个例子中,Card.vue 组件有两个插槽:一个具名插槽 header 和一个默认插槽。

父组件:App.vue

接下来,在父组件中,我们将使用 CardDemo.vue 并为插槽内容应用样式。

复制代码
<template>
  <div id="app">
    <card-demo>
      <template v-slot:header>
        <h2 class="card-title">Custom Header</h2>
      </template>
      <template v-slot:default>
        <p class="card-text">This is a custom paragraph inside the card.</p>
      </template>
    </card-demo>
  </div>
</template>
 
<script>
import CardDemo from './components/CardDemo.vue';
 
export default {
  components: {
    CardDemo
  }
};
</script>
 
<style scoped>
/* 父组件的样式 */
 .card-title {
  color: red;
}
 
 .card-text {
  font-weight: bold;
  color:blue;
}
</style>

写在最后.

能入手一个可以的项目. 框架是基础. 底层的js+html+css 也需要打牢.

博主也完结了 前端 基础课程 .参考 https://blog.csdn.net/chxii/category_12913839.html

相关推荐
崔庆才丨静觅13 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby606114 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了14 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅14 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅14 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅15 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment15 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅15 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊15 小时前
jwt介绍
前端
爱敲代码的小鱼15 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax