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

<app>
<app-header></app-header>
<app-footer></app-footer>
</app>

注意两点:

  1. <app> 组件不知道它会收到什么内容。这是由使用 <app> 的父组件决定的。

  2. <app> 组件很可能有它自己的模板。

为了让组件可以组合,我们需要一种方式来混合父组件的内容与子组件自己的模板。这个过程被称为内容分发 (即 Angular 用户熟知的“transclusion”)。Vue.js 实现了一个内容分发 API,参照了当前 Web Components 规范草案,使用特殊的 <slot> 元素作为原始内容的插槽。

编译作用域

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

<child-component>
{{ message }}
</child-component>

message 应该绑定到父组件的数据,还是绑定到子组件的数据?答案是父组件。组件作用域简单地说是:

父组件模板的内容在父组件作用域内编译;子组件模板的内容在子组件作用域内编译

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

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

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

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

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

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

单个插槽

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

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

slot相当于子组件设置了一个地方,如果在调用它的时候,往它的开闭标签之间放了东西,那么它就把这些东西放到slot中。

  1. 当子组件中没有slot时,父组件放在子组件标签内的东西将被丢弃;

  2. 子组件的slot标签内可以放置内容,当父组件没有放置内容在子组件标签内时,slot中的内容会渲染出来;

  3. 当父组件在子组件标签内放置了内容时,slot中的内容被丢弃

子组件的模板:

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

父组件模板:

<div>
<h1>我是父组件的标题</h1>
<my-component>
<p>这是一些初始内容</p>
</my-component>
</div>

渲染结果:

<div>
<h1>我是父组件的标题</h1>
<div>
<h2>我是子组件的标题</h2>
<p>这是一些初始内容</p>
</div>
</div>

具名插槽

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

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

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

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

父组件模板:

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

渲染结果为:

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

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

作用域插槽

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

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

<div class="child">
<slot text="hello from child"></slot>
</div>

在父级中,具有特殊特性 slot-scope 的 <template> 元素必须存在,表示它是作用域插槽的模板。slot-scope 的值将被用作一个临时变量名,此变量接收从子组件传递过来的 prop 对象:

<div class="parent">
<child>
<template slot-scope="props">
<span>hello from parent</span>
<span>{{ props.text }}</span>
</template>
</child>
</div>

如果我们渲染上述模板,得到的输出会是:

<div class="parent">
<div class="child">
<span>hello from parent</span>
<span>hello from child</span>
</div>
</div>

在 2.5.0+,slot-scope 能被用在任意元素或组件中而不再局限于 <template>

作用域插槽更典型的用例是在列表组件中,允许使用者自定义如何渲染列表的每一项:

<my-awesome-list :items="items">
<!-- 作用域插槽也可以是具名的 -->
<li
slot="item"
slot-scope="props"
class="my-fancy-item">
{{ props.text }}
</li>
</my-awesome-list>

列表组件的模板:

<ul>
<slot name="item"
v-for="item in items"
:text="item.text">
<!-- 这里写入备用内容 -->
</slot>
</ul>

解构

slot-scope 的值实际上是一个可以出现在函数签名参数位置的合法的 JavaScript 表达式。这意味着在受支持的环境 (单文件组件或现代浏览器) 中,您还可以在表达式中使用 ES2015 解构:

<child>
<span slot-scope="{ text }">{{ text }}</span>
</child>

Vue组件-使用插槽分发内容的更多相关文章

  1. vue组件-使用插槽分发内容(slot)

    slot--使用插槽分发内容(位置.槽口:作用: 占个位置) 官网API: https://cn.vuejs.org/v2/guide/components.html#使用插槽分发内容 使用组件时,有 ...

  2. Vue结合slot插槽分发父组件内容实现高度复用、更加灵活的dialog组件

    之前写过一篇关于vue实现dialog会话框组件的文章(http://www.cnblogs.com/fozero/p/8546883.html)[http://www.cnblogs.com/foz ...

  3. 使用Vue的slot插槽分发父组件内容实现高度复用、更加灵活的组件

    写在前面 之前写过一篇关于vue实现dialog会话框组件的文章http://www.cnblogs.com/fozero/p/8546883.html, 讲到了如何实现一个vue对话框组件,其中涉及 ...

  4. vue使用插槽分发内容slot的用法

    将父组件的内容放到子组件指定的位置叫做内容分发 //在父组件里使用子组件 <son-tmp> <div>我是文字,我需要放到son-tmp组件里面制定的位置</div&g ...

  5. vue 通过插槽分发内容

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  6. vue2.0使用slot插槽分发内容

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  7. Vue组件化和路由

    组件化 组件化是vue的核心思想,它能提高开发效率,方便重复使用,简化调试步骤,提升整个项目的可维护性,便于多人协同开发 组件通信 父组件 => 子组件: 属性props 特性$attrs 引用 ...

  8. 详解Vue中的插槽

    作者: 小土豆 博客园:https://www.cnblogs.com/HouJiao/ 掘金:https://juejin.im/user/2436173500265335 什么是插槽 在日常的项目 ...

  9. vue学习之插槽

    插槽 插槽(Slot)是Vue提出来的一个概念,正如名字一样,插槽用于决定将所携带的内容,插入到指定的某个位置,从而使模板分块,具有模块化的特质和更大的重用性. 个人理解:我感觉插槽就是父组件控制插槽 ...

随机推荐

  1. udp->ip & tcp->ip 发送数据包的目的地址的源地址是什么时候确定的?

    udp->ip & tcp->ip udp到ip层是:ip_send_skb tcp到ip层是: ip_queue_xmit 拿tcp为例,在使用[ip_queue_xmit, i ...

  2. [C/C++] 原码、反码、补码问题

    正确答案:D 解析: C语言中变量以补码形式存放在内存中,正数的补码与原码相同,负数求补码方式为(符号位不变,其余各位取反,最后末尾加1): 32位机器:int 32位,short 16位.  x = ...

  3. usebean 使用语法

  4. BZOJ 1791 岛屿(环套树+单调队列DP)

    题目实际上是求环套树森林中每个环套树的直径. 对于环套树的直径,可以先找到这个环套树上面的环.然后把环上的每一点都到达的外向树上的最远距离作为这个点的权值. 那么直径一定就是从环上的某个点开始,某个点 ...

  5. 【bzoj1231】[Usaco2008 Nov]mixup2 混乱的奶牛 状态压缩dp

    题目描述 混乱的奶牛[Don Piele, 2007]Farmer John的N(4 <= N <= 16)头奶牛中的每一头都有一个唯一的编号S_i (1 <= S_i <= ...

  6. openjudge666:放苹果—题解

    (测试这里的markdown,同时也有纪念意义吧--第一次写的题解) 当时刚学递推的时候做的一道题 oj上的666题 666:放苹果 总时间限制: 1000ms 内存限制: 65536kB 描述 把M ...

  7. Java第一次实验报告——Java开发环境的熟悉

    北京电子科技学院(BESTI) 实    验    报    告 课程名称:java程序设计实验      班级:1352         姓名:洪韶武      学号:20135219 成绩:   ...

  8. 「LibreOJ NOIP Round #1」七曜圣贤

    题目啰嗦:支持三个操作: 不可重复集合:1.加入一个数 2.删除一个数 3.恢复目前最早的一次删除的数 操作可能不合法,每次有效操作之后求集合的mex(最小没有出现过的数) 50组数据+1e6,必须O ...

  9. POI 2018.10.22

    [POI2015]ODW 喵锟讲过.分块. N>=blo,那就暴力倍增往上跳.O(N/blo*logN) N<blo,预处理,f[i][j]表示,i往上跳,每次跳j步,到根节点为止,权值和 ...

  10. 添加网站标题logo

    如何在标题栏title前添加网站logo? 第一种方法:据说在网站根目录下放着我们的ico型logo,命名为favicon.ico,浏览器会自动去找到并显示.试了试,在firefox23和ie8下都没 ...