Vue组件基础内容:插槽、动态组件(二)

插槽

插槽内容

建立一个组件,组件的使用通常用其名字组成的标签,例如<myComponent>组件标签里的内容</myComponent>,在这两个标签的中间,我们可以插入一些内容,这些内容是根据需求可要可不要的,但谁知道到底什么时候会需要呢?并且,自定义组件标签便是组件模板本身,不同于原生标签那样简单。如果组件标签会被渲染成组件模板,那组件标签内的内容该渲染在哪里?于是,插槽的作用显现了。在模板内某个想要插入组件标签内容的地方,放置一对<slot></slot>,这个标签被称为插槽。插槽功能很强大,第一个功能便是上述场景,<slot></slot>可在模板某个位置事先安插,用来动态盛放并在渲染时显示组件标签里的内容。

// 组件及其标签内容
<myComponent>组件标签里的内容</myComponent>

// myComponent 组件本身
<template>
<div id="app">
<slot></slot>
</div>
</template>

// 渲染后
<div id="app">
组件标签里的内容
</div>

后备内容

与第一种作用相反,插槽作为内容分发工具,不仅仅可以作为预留空间承载组件标签里的内容,也可以提前放置内容作为组件标签内容的预备。

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

// 组件标签有内容
<submit-button>
  Save
</submit-button>

// 组件标签无内容
<submit-button>
</submit-button>

// 渲染后的 element
<button type="submit">
  Submit
</button>

插槽编译作用域

上面提到,组件标签里可以插入内容,只是需要插槽来呈现这些内容,插槽也可以设置后备内容,当组件标签没有内容时作为备用选择。

当作为呈现子组件标签内容的功能时,子组件标签里如果使用了父组件作用域的数据,插槽作为承载工具可以接收到这些内容。但如果插槽作为后备内容的作用时,插槽使用了所在子组件作用域的数据,希望可以作为子组件标签的后备内容时,是没办法传递这些数据给子组件标签的,因为子组件标签已经处在了父级作用域:

// 子组件模板
<div class="hello">
    <slot></slot>
  </div>

// 子组件标签
<HelloWorld>
      {{message}}
</HelloWorld>

// 子组件标签所在父组件的 data
data () {
    return {
      message: '我是父组件内容'
    }
}

// 以上内容可以渲染
// 子组件模板
<div class="hello">
    <slot>{{ message }}</slot>
</div>

// 子组件标签
<HelloWorld>
</HelloWorld>

// 子组件的 data
data () {
    return {
      message: '我是子组件的内容'
    }
}

// 插槽里的 message 作为后备内容无法传递给子组件标签

具名插槽

在前面,我们提到插槽的两个作用,一个是为组件标签提供预设内容,一个是作为承载组件标签内容的预留空间,刚好是一个互补的作用。在这里,具名插槽的意思就是插槽有名字,它的渲染位置可以通过名字来确定。这个具名插槽的作用发挥的是第二种作用:作为承载组件标签内容的预留空间。比如,组件模板已经比较臃肿了,但我又想在模板里加上一些东西,这时我可以在组件标签里设置了一些内容,希望被渲染到组件模板的具体某个位置,便可以使用具名插槽。实现在组件标签里铺设内容;

<base-layout>
  <template v-slot:header>
    <h1>Here might be a page title</h1>
  </template>

  <p>A paragraph for the main content.</p>
  <p>And another one.</p>

  <template v-slot:footer>
    <p>Here's some contact info</p>
  </template>
</base-layout>

可以看到这里的组件标签里的东西类似于一个迷你模板,在上面有一个指令:v-slot,指定了该“模板”的渲染在哪个插槽的位置:

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

这是 base-layout 的模板,可以在这里实现安插插槽,并给插槽一个名字,组件标签里的迷你模板将会被渲染到指定的插槽所在的位置。没有给定插槽名字的插槽拥有一个默认名字:default。

作用域插槽

这个插槽释放了插槽的强大能力。在前面,我们提到,子组件标签在父组件里渲染,当希望 slot 可以使用子组件的数据设置后备内容时,子组件标签并不能接收到子组件里的 data 等数据。

但作用域插槽突破了这个限制,可在子组件插槽添加属性:v-bind:user="user"

<div class="helloworld">
    <slot v-bind:user="user"></slot>
  </div>

这样,子组件的数据被传递到一个 slotProps 的对象上,当然,这个名字可以自定义。可以在子组件标签里这么使用:

<HelloWorld>
    <template v-slot:default="slotProps">
        {{ slotProps.user.firstName }}
    </template>
</HelloWorld>

这样,子组件里的数据便可以子组件标签里使用。同样的,让我们串联起前面具名插槽的知识,这里的 default 指定了插槽的名字,可以更改插槽名字指定使用哪个插槽作为渲染的容器。

但不得不吐槽的是,在子组件里的数据,费尽九牛二虎之力传到子组件标签所在父组件的作用域里,但渲染后这些内容却又是被渲染回子组件里。这样的折腾实在不知有何意义。也不知有何使用场景,暂且可搁置在一旁。

插槽的作用其实十分强大,但目前来说暂时没有驾驭它的能力,对插槽的使用场景尚无经验,可对上述基本功能做下掌握。

动态组件

想象一下以下场景,点击一个 tab 切换不同的页面。这是一个十分常见的需求,可以使用不同的组件承载不同的内容,点击以下切换组件。除了 v-if 的实现方式,还可以使用 is attribute 来切换不同的组件官方案例
现在,已经可以通过 is attribute 实现组件的切换。但你会注意到,如果你选择了一篇文章,切换到 Archive 标签,然后再切换回 Posts,是不会继续展示你之前选择的文章的。这是因为你每次切换新标签的时候,Vue 都创建了一个新的 currentTabComponent 实例。

但如果我们希望切换时组件的状态会被保留,就需要用到 keep-alive 元素的强大能力了。

<!-- 失活的组件将会被缓存!-->
<keep-alive>
  <component v-bind:is="currentTabComponent"></component>
</keep-alive>

这样,组件状态就会被缓存。当你来回切换组件时,你在组件上的操作状态将会被保留,组件不会每次都被刷新,这对于一些无更新的组件来说实现了高效复用。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,444评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,421评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,363评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,460评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,502评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,511评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,280评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,736评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,014评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,190评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,848评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,531评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,159评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,411评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,067评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,078评论 2 352

推荐阅读更多精彩内容