Vue 插槽(slot)

港控/mmm° 2023-05-31 12:05 94阅读 0赞

我们经常需要使用插槽分发内容。

在使用组件时,我们常常要像这样组合它们:

  1. <app>
  2. <app-header></app-header>
  3. <app-footer></app-footer>
  4. </app>

注意两点:

  • 组件不知道它会收到什么内容。这是由使用 的父组件决定的。
  • 组件很可能有它自己的模板。

为了让组件可以组合,我们需要一种方式来混合父组件的内容与子组件自己的模板。这个过程被称为内容分发 (即 Angular 用户熟知的“transclusion”)。

Vue.js 实现了一个内容分发 API,参照了当前 Web Components 规范草案,使用特殊的 元素作为原始内容的插槽。

编译作用域

在深入内容分发 API 之前,我们先明确内容在哪个作用域里编译。假定模板为:

  1. <child-component>
  2. {
  3. { message }}
  4. </child-component>

message 应该绑定到父组件的数据,还是绑定到子组件的数据?答案是父组件。

组件作用域简单地说是:父组件模板的内容在父组件作用域内编译;子组件模板的内容在子组件作用域内编译。

一个常见错误是试图在父组件模板内将一个指令绑定到子组件的属性/方法:

  1. <!-- 无效 -->
  2. <child-component v-show="someChildProperty"></child-component>

假定 someChildProperty 是子组件的属性,上例不会如预期那样工作。父组件模板并不感知子组件的状态。

如果要绑定子组件作用域内的指令到一个组件的根节点,你应当在子组件自己的模板里做:

  1. Vue.component('child-component', {
  2. // 有效,因为是在正确的作用域内
  3. template: '<div v-show="someChildProperty">Child</div>',
  4. data: function () {
  5. return {
  6. someChildProperty: true
  7. }
  8. }
  9. })

类似地,被分发的内容会在父作用域内编译。

单个插槽

除非子组件模板包含至少一个 插口,否则父组件的内容将会被丢弃。当子组件模板只有一个没有属性的插槽时,父组件传入的整个内容片段将插入到插槽所在的 DOM 位置,并替换掉插槽标签本身。

最初在 标签中的任何内容都被视为备用内容。备用内容在子组件的作用域内编译,并且只有在宿主元素为空,且没有要插入的内容时才显示备用内容。

假定 my-component 组件有如下模板:

  1. <div>
  2. <h2>我是子组件的标题</h2>
  3. <slot>
  4. 只有在没有要分发的内容时才会显示。
  5. </slot>
  6. </div>

父组件模板:

  1. <div>
  2. <h1>我是父组件的标题</h1>
  3. <my-component>
  4. <p>这是一些初始内容</p>
  5. <p>这是更多的初始内容</p>
  6. </my-component>
  7. </div>

渲染结果:

  1. <div>
  2. <h1>我是父组件的标题</h1>
  3. <div>
  4. <h2>我是子组件的标题</h2>
  5. <p>这是一些初始内容</p>
  6. <p>这是更多的初始内容</p>
  7. </div>
  8. </div>

具名插槽

元素可以用一个特殊的特性 name 来进一步配置如何分发内容。多个插槽可以有不同的名字。具名插槽将匹配内容片段中有对应 slot 特性的元素。

仍然可以有一个匿名插槽,它是默认插槽,作为找不到匹配的内容片段的备用插槽。如果没有默认插槽,这些找不到匹配的内容片段将被抛弃。

例如,假定我们有一个 app-layout 组件,它的模板为:

  1. <div class="container">
  2. <header>
  3. <slot name="header"></slot>
  4. </header>
  5. <main>
  6. <slot></slot>
  7. </main>
  8. <footer>
  9. <slot name="footer"></slot>
  10. </footer>
  11. </div>

父组件模板:

  1. <app-layout>
  2. <h1 slot="header">这里可能是一个页面标题</h1>
  3. <p>主要内容的一个段落。</p>
  4. <p>另一个主要段落。</p>
  5. <p slot="footer">这里有一些联系信息</p>
  6. </app-layout>

渲染结果为:

  1. <div class="container">
  2. <header>
  3. <h1>这里可能是一个页面标题</h1>
  4. </header>
  5. <main>
  6. <p>主要内容的一个段落。</p>
  7. <p>另一个主要段落。</p>
  8. </main>
  9. <footer>
  10. <p>这里有一些联系信息</p>
  11. </footer>
  12. </div>

在设计组合使用的组件时,内容分发 API 是非常有用的机制。

作用域插槽

作用域插槽是一种特殊类型的插槽,用作一个 (能被传递数据的) 可重用模板,来代替已经渲染好的元素。

在子组件中,只需将数据传递到插槽,就像你将 prop 传递给组件一样:

  1. <div class="child">
  2. <slot text="hello from child"></slot>
  3. </div>

在父级中,具有特殊特性 slot-scope 的

发表评论

表情:
评论列表 (有 0 条评论,94人围观)

还没有评论,来说两句吧...

相关阅读

    相关 vue slot

    一、介绍:slot可以理解为占位符,在子组件中给父组件站位。 二、举例说明: 1、没有插槽: (1)父组件: <template> <div>

    相关 vueslot)详解

    最近被问起是否了解vue的插槽(slot),咋一想发现,似乎很少用到这玩意。所以整理了下slot的一些用法。 slot (父组件 在子组件<slot> </slot>处插入

    相关 Vue slot

    我们对于slot这个概念或许不是很清楚,但是我们在实际的使用中可能已经遇到很多次了。比如我们在使用ivew组件库的时候,就会经常遇到slot这个单词。而实际上,slot的使用更

    相关 Vue(slot)

    slot:向组件内部指定位置传递内容 单个插槽(匿名插槽) 在App.vue引入子组件About.vue,在about标签加上一个div标签传递到子组件中: Ap