vue插槽详解

声明:在 2.6.0 中,我们为具名插槽和作用域插槽引入了一个新的统一的语法 (即 'v-slot' 指令)。它取代了 'slot' 和 'slot-scope'这两个目前已被废弃但未被移除且仍在文档中的attribute,本文我们仅仅针对vue2.6及以上版本的插槽语法进行讲解!

一、什么是插槽?

1、定义

官方解释:插槽就是Vue实现的一套内容分发的API,将<slot></slot>元素作为承载分发内容的出口。
通俗解释:想要在一个组件标签中,加入一些内容,那就必须要在组件内声明slot元素,否则不会被渲染出来。

2、举个栗子

有这样一个自定义组件navigation-link,在父组件中使用:

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

navigation-link组件封装如下:

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

当组件渲染的时候,<slot></slot> 将会被替换为“Your Profile”。假设navigation-link组件中不写<slot></slot>,那么组件标签中间加入的任何内容都不会生效。

tips:插槽内可以包含任何模板代码,包括 HTML:例子如下

<navigation-link url="/profile">
  <!-- 添加一个 Font Awesome 图标 -->
  <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>

二、具名插槽

1、定义

具名插槽,就是给这个插槽起个名字。一个子组件可以放多个插槽,而且可以放在不同的地方,而父组件填充内容时,可以根据这个名字把内容填充到对应插槽中。

2、如何使用

<slot> 元素有一个特殊的 attribute:name。这个name属性的值就是插槽的名字,父组件中在一个 <template> 元素上使用v-slot 指令,并以 v-slot 的参数的形式提供其名称,一一对应。

2、举个栗子

有这样一个组件<base-layout>,给它创建三个插槽

<div class="container">
   <header>
       <slot name="header"></slot>
   </header>
   <main>
       <!-- 不带 name 的 <slot> 出口会带有隐含的名字“default”,即默认插槽-->
       <slot></slot> 
   </main>
   <footer>
       <slot name="footer"></slot>
   </footer>
</div>

父组件中代码如下:

<base-layout>
  <template v-slot:header>
    <h1>Here might be a page title</h1>
  </template>
   <!-- 没有被包裹在带有 v-slot 的 <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>

三、作用域插槽

1、背景

看个栗子: 还记得前面提到的navigation-link组件吗?假设我们想在这个父模板中使用传递给子组件的数据url,是会拿不到的,这里url会是undefined

<navigation-link url="/profile">
  点击这里跳转: {{ url }}
  <!--
  这里的 `url` 会是 undefined,因为其 (指该插槽的) 内容是
  _传递给_ <navigation-link> 的而不是
  在 <navigation-link> 组件*内部*定义的。
  -->
</navigation-link>

谨记一条规则:
父级模板里的所有内容都是在父级作用域中编译的;
子模板里的所有内容都是在子作用域中编译的。
所以想在父作用域中访问子组件中的数据,那我们的作用域插槽就派上了用场啦~

2、概念

作用域插槽其实就是带数据的插槽,简单点说就是子组件提供给父组件的数据,父组件可根据子组件传过来的插槽数据来进行不同的方式展现和填充插槽内容。

3、举个栗子

有这样一个导航组件nav-link

<ul>
     // navLists是父组件传递过来的数据,放在props中(props:['navLists'])
     <li v-for="list in navLists"> 
        <a :href="list.url" class="nav-link">
            <slot :rowData="list">{{list.name}}</slot>
        </a>
    </li>
</ul>

父组件中代码

//数据如下:
<!--
lists: [
    {name:'首页', url:'/home'},
    {name:'关于', url:'/about'},
    {name:'新闻', url:'/news'}
  ]
-->
<nav-link :navLists="lists">
    <template v-slot:default="slotProps">
        {{slotProps}}
    </template>
</nav-link>

页面显示如下:


假设现在我们想展示的更个性化一点,让首页导航前面显示一个小图标,那应该怎么做?

<nav-link :navLists="lists">
    <template v-slot:default="slotProps">
      <span v-if="slotProps.rowData.name==='首页'">
          <font-awesome-icon name="home" />{{slotProps.rowData.name}}
       </span>
      <span v-else>{{slotProps.rowData.name}}</span>
    </template>
</nav-link>

tips1: 默认插槽的缩写形式
上面例子中因为子组件slot元素未设置name属性,所以就是默认插槽,因此’v-slot:default="slotProps"可以缩写为v-slot="slotProps",但是缩写语法不能和具名插槽混用,否则会导致作用域不明确。如果出现多个插槽时,请始终为所有的插槽使用完整的基于 <template> 的语法:

<nav-link :navLists="lists">
  <template v-slot:default="slotProps">
    {{ slotProps.rowData.name }}
  </template>

  <template v-slot:other="otherSlotProps">
    ...
  </template>
</nav-link>

tips2: 解构插槽Prop
作用域插槽的内部工作原理是将你的插槽内容包括在一个传入单个参数的函数里,因此v-slot的值实际上可以是任何能够作为函数定义中的参数的 JavaScript 表达式

<nav-link :navLists="lists">
    <template v-slot="{ rowData }">
      <span v-if="rowData.name==='首页'">
          <font-awesome-icon name="home" />{{.rowData.name}}
       </span>
      <span v-else>{{rowData.name}}</span>
    </template>
</nav-link>

哈哈,上面这种写法,用过element-ui的童鞋们,是不是觉得超级熟悉,在表格中,我们要自定义某列数据的时候,经常会用到slot-scope(也就是文中提到的v-slot,因为下图中的项目代码还是之前用的vue2.5,而v-slot是我们vue2.6以上新出来的语法), 其实表格的本质就是这样!


四、总结

v-slot用法简记:
:后面是插槽名称
=后面是组件内部绑定作用域值得映射

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