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

相关推荐
_Kayo_1 小时前
CSS BFC
前端·css
二哈喇子!2 小时前
Vue3 组合式API
前端·javascript·vue.js
二哈喇子!4 小时前
Vue 组件化开发
前端·javascript·vue.js
姑苏洛言5 小时前
扫码点餐小程序产品需求分析与功能梳理
前端·javascript·后端
Freedom风间5 小时前
前端必学-完美组件封装原则
前端·javascript·设计模式
江城开朗的豌豆5 小时前
React表单控制秘籍:受控组件这样玩就对了!
前端·javascript·react.js
一枚前端小能手5 小时前
📋 代码片段管理大师 - 5个让你的代码复用率翻倍的管理技巧
前端·javascript
国家不保护废物5 小时前
Web Worker 多线程魔法:告别卡顿,轻松实现图片压缩!😎
前端·javascript·面试
接着奏乐接着舞。5 小时前
如何在Vue中使用拓扑图功能
前端·javascript·vue.js