一篇文章带你了解 “Vue 插槽”__Vue.js
发布于 4 年前 作者 banyungong 2004 次浏览 来自 分享
粉丝福利 : 关注VUE中文社区公众号,回复视频领取粉丝福利

vue插槽

1.什么是插槽?

Vue 实现了一套内容分发的 API,这套 API 的设计灵感源自 Web Components 规范草案,将 <slot> 元素作为承载分发内容的出口。</slot>

它允许你像这样合成组件:

<person-name v-slot='slotProps'>
  <ul>
    <li v-for='item in slotProps.data'>{{item}}</li>
  </ul>
</person-name>

然后你在 <person-name> 的模板中可能会写为:

<div>
  <slot :data='persons' :age='age'></slot>
</div>

实现效果:

插槽就相当于把一个组件变成一个html标签,可以在里面添加元素或者其它的组件。

2.什么是具名插槽?

具名插槽,从它的名字我们可能会猜想它到就是一个有名字的插槽。

「官网解释」: 有时我们需要多个插槽。例如对于一个带有如下模板的 <base-layout> 组件:</base-layout>

<div class="container">
  <header>
    <!-- 我们希望把页头放这里 -->
  </header>
  <main>
    <!-- 我们希望把主要内容放这里 -->
  </main>
  <footer>
    <!-- 我们希望把页脚放这里 -->
  </footer>
</div>

对于这样的情况,<slot> 元素有一个特殊的 attribute:name。这个 attribute 可以用来定义额外的插槽:</slot>

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

一个不带 name 的 <slot> 出口会带有隐含的名字“default”。也就是默认插槽。

在向具名插槽提供内容的时候,我们在 <template>元素上使用 v-slot 指令,并以 v-slot 的参数的形式提供其名称

<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>

「注意」:

1.任何没有被包裹在带有 v-slot<template> 中的内容都会被视为默认插槽的内容。(相当于是在v-slot:default中)

<template v-slot:default>
  <p>A paragraph for the main content.</p>
  <p>And another one.</p>
</template>

2.具名插槽中的 v-slot 只能添加在 <template> 上 (只有一种例外情况,就是当被提供的内容只有默认插槽时,组件的标签才可以被当作插槽的模板来使用。这样我们就可以把 v-slot 直接用在组件上)

<person-name #default='slotProps'>
  <template >
    <button v-for='item in slotProps.data'>{{item}}</button>
  </template>
</person-name>

(上面的#defaultv-slot:default的缩写。当是具名插槽时,只需要把 default 换成具名插槽的名字即可)

实现效果:

3.作用域插槽

绑定在 <slot> 元素上的 attribute 被称为插槽 prop。现在在父级作用域中,我们可以使用带值的 v-slot 来定义我们提供的插槽 prop 的名字。

拿上一段代码为例:

这是<person-name>组件的模板

<div>
  <slot :data='persons' :age='age'></slot>
</div>

向插槽中插入button按钮

<person-name v-slot='slotProps'>
  <!-- 只有一个插槽时(默认插槽) v-slot后面的参数可以省略 -->
  <template >
    <button v-for='item in slotProps.data'>{{item}}</button>
  </template>
</person-name>

插槽中的prop:

persons:['Tom','xioaming','Jan','Lile','Damin'],
age: [1,2,3,4,5]

在这个例子中,我们选择将包含所有插槽 prop 的对象命名为 slotProps,但你也可以使用任意你喜欢的名字。

结果和上图一样:

4.解构插槽

作用域插槽的内部工作原理是将你的插槽内容包括在一个传入单个参数的函数里:

function (slotProps) {
  // 插槽内容
}

这意味着 v-slot 的值实际上可以是任何能够作为函数定义中的参数的 JavaScript 表达式。所以在支持的环境下 (单文件组件或现代浏览器),你也可以使用 ES2015 解构来传入具体的插槽 prop,如下:

<person-name v-slot='{ data }'>
  <ul>
    <li v-for='item in data'>{{item}}</li>
  </ul>
</person-name>

这样可以使模板更简洁,尤其是在该插槽提供了多个 prop 的时候。它同样开启了 prop 重命名等其它可能,例如将 data 重命名为 slotProps:

<person-name v-slot='{ data: slotProps }'>
  <ul>
    <li v-for='item in slotProps'>{{item}}</li>
  </ul>
</person-name>

你甚至可以定义后备内容,用于插槽 prop 是 undefined 的情形:

<person-name v-slot='{ user = { firstName: [1,2,3,4,5]} }'>
  <template >
    <select v-model='num'>
      <option v-for='item in user.firstName'>{{item}}</option>
    </select>
    <span>{{num}}</span>
  </template>
</person-name>

实现效果:

5.如何添加动态插槽名?

动态指令参数也可以用在 v-slot 上,来定义动态的插槽名:

<base-layout>
  <template v-slot:[dynamicSlotName]>
    ...
  </template>
</base-layout>

这里的 dynamicSlotName 会被作为一个 JavaScript 表达式进行动态求值,求得的值将会作为最终的参数来使用。例如,如果你的 Vue 实例有一个 data property dynamicSlotName,其值为 "name",那么这个绑定将等价于 v-bind:name

6.slot 和 slot-scope

v-slot 指令自 Vue 2.6.0 起被引入,提供更好的支持 slotslot-scope attribute 的 API 替代方案。在接下来所有的 2.x 版本中 slotslot-scope attribute 仍会被支持,但已经被官方废弃且不会出现在 Vue 3 中。

<person-name v-slot='{data: slotProps}'>
  <!-- v-slot 代替了这种写法 -->
  <!-- <template slot="default" slot-scope="slotProps">
      <ul>
        <li v-for='item in slotProps.data'>{{item}}</li>
      </ul>
  </template> -->
  <ul>
    <li v-for='item in slotProps'>{{item}}</li>
  </ul>
</person-name>

上面带注释的代码和没注释的代码实现效果相同。

文章部分内容引用vue官网,如果有错误,欢迎大家指正。

版权声明:著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 作者: 听见下雨声 原文链接:https://juejin.im/post/6857161745098768391

回到顶部