Vue | 15 组件深入-插槽

内容提要:

  1. 插槽的内容
  2. 命名的插槽
  3. 默认插槽内容
  4. 插槽的编译范围
  5. 作用域插槽
  6. 解构slot-scope

这页假定你已经阅读组件基础( Components Basics),如果你不了解组件,请先阅读它。

插槽内容

Vue实现了一套内容分发的API。该API基于当前Web组件规范草案 Web Components spec draft。使用slot元素去作为内容分发的出口。

这允许你去像这样组成组件:

<navigation-link url="/profile">
    Your Profile
</navigation-link>

然后,在navigaiton-link标签的模板中,你可以有:

<a
   v-bind:href="url"
   class="nav-link">
    <slot></slot>
</a>

当组件渲染的时候,slot标签元素将被“Your Profile”替换,Slots能包含任何模板代码,包括HTML:

<navigation-link url="/profile">
    <!-- Add a Font Awesome icon -->
    <span class="fa fa-user"></span>
    Your Profile
</navigation-link>

或者甚至其他组件:

<navigation-link url="/profile">
    <!-- 使用组件去增加一个图标 -->
    <font-awesome-icon name="user"></font-awesome-icon>
    Your Profile
</navigation-link>

如果navigation-link元素不包含slot标签元素,任何传递给它的内容仅仅会被丢弃。

被指名的插槽

有时候我们需要多个插槽,例如,假设base-layout组件使用以下模板:

<div class="container">
    <header>
        <!-- header内容 -->
    </header>
    <main>
        <!-- main内容 -->
    </main>
    <footer>
        <!-- footer内容 -->
    </footer>
</div>

对于这些事例,slot标签元素有一个特定属性,name可用于定义额外插槽:

<div class="container">
    <header>
        <slot name="header"></slot>
    </header>
    <main>
        <slot></slot>
    </main>
    <footer>
        <slot name="footer"></slot>
    </footer>
</div>

去提供内容给被命名的slots,我们能够使用template标签元素的slot属性在父节点。

<base-layout>
    <template slot="header">
        <h1>这可能是一个页的标题</h1>
    </template>
    
    <p>段落主要内容</p>
    <p>另一段</p>
    
    <template solt="footer">
        <p>这有一些联系人信息</p>
    </template>
</base-layout>

或,slot属性能被直接的用在一个正常的元素:

<base-layout>
    <h1 slot="header">这可能是本页的标题</h1>
    
    <p>这段的主要内容</p>
    <p>另一段</p>
    
    <p slot="footer">这是一些联信息</p>
</base-layout>

仍然可能有一个未命名的插槽,这是一个默认插槽,用于为不匹配的内容提供通配符输出。在以上这些例子,HTML将被渲染:

<div class="container">
    <header>
        <h1>这可能是一个标题</h1>
    </header>
    <main>
        <p>一段主要内容</p>
        <p>另一段</p>
    </main>
    <footer>
        <p>这是一些联系信息</p>
    </footer>
</div>

默认插槽内容

在一些情况下,提供一个默认内容的插槽可能是有用的。例如,一个submit-button元素组件可能需要默认的Submit的按钮内容,但是也允许用于用“Save”,“Upload”,或其他任何内容复写。

为了实现这个,在你的组件模板的标签之间指定默认内容:

<butotn type="submit">
    <slot>Submit</slot>
</butotn>

如果插槽通过父节点提供了内容,它将会替换默认内容。

编译范围

当你想在一个插槽内使用数据的时候,像这样:

<navigaiton-link url="/profile">
    Logged in as {{ user.name }}
</navigaiton-link>

插槽可以访问和模板的清汤地方相同的实例属性(即“作用域”相同)。插槽不能够访问navigaiton-link标签的作用域,例如,试着去访问url将没办法工作,作为一个规则,记住:

在父模板的每一件事情在父作用域编译,在子模板的每一件事情在子作用域编译。

插槽作用域

在 2.1.0新增

有时你可能想要提供一个组件带有一个能从子组件访问数据的可复用的插槽。例如,一个简单的todo-list元素组件可能包含以下模板:

<ul>
    <li
        v-for="todo in todos"
        v-bind:key="todo.id">
    </li>
    {{ todo.text }}
</ul>

但是在我们app的某些部分,我们想要一些特别的操作项去渲染不用于todo.text的内容。这就是作用域卡槽带来的作用。

为了使这个功能成为可能,我们不得不在一个元素封装所有todo 列表内容,然后传递给slot任何相关的内容数据: 在这个例子中,使用todo对象:

<ul>
    <li
        v-for="todo in todos"
        v-bind:key="todo.id">
        <!-- 我们为每一个插槽创建一个todo,传递给它‘todo’对象作为一个slot prop -->
        <slot v-bind:todo="todo">
            <!-- 回退的内容 -->
            {{ todo.text }}
    </li>
</ul>

现在当我们使用todo-list元素组件的时候,我们可以选择为待办事项选择一个替代方案template元素,但是从子组件的slot-scope属性访问数据:

<todo-list v-bind:todos="todos">
    <!-- 定义一个'slotProps'作为我们slot作业域的名字 -->
    <template slot-scope="slotProps">
        <!-- 为todo items 定义一个自定义模板,使用`slotProps`to自定义每一个todo -->
        <span v-if="slotProps.todo.isComplete"></span>
        {{ slotProps.todo.text }}
    </template>
</todo-list>

在2.5.0+,slot-scope不再被 元素限制,而是能够替代使用在slot的任何组件或元素。

解构slot-scope

slot-scope的值实际上能接受任何出现在函数定义的参数位置的JavaScript表达式。意思是说在支持的环境下(single-file components or modern browsers)你能够在表达式中使用 ES2015 destructuring 解构语法,例如:

<todo-list v-bind:todos="todos">
    <template slot-scope="{ todo }">
        <span v-if="todo.isComplete">✓</span>
        {{ todo.text }}
    </template>
</todo-list>

这会使作用域插槽更干净一些。

猜你喜欢

转载自blog.csdn.net/wudizhanshen/article/details/84851743