vue总结系列 --- 插槽slot

前因

这个是我这个系列的第二篇,这一篇文章我也修改过三次(2019-9-10)我是想以vue官方文档为基础,来进行理解,有人说有官方文档,还要写自己的文章干嘛,我的用意其实是我确实想把官网文档中的案例全部写一遍,来加深自己对这个知识点的理解,因为看还是不如写吧,我在吧我遇到的问题,和我的理解,写出来,以便我以后的忘记,和与我有类似经历的人不用再浪费时间

插槽

其实就是在组件的innerHTML中的内容,他会传递给这个组件中的<slot>元素,其实从功能上来看这个过程有点像prop,但用prop是传递的属性值,而插槽传递的是文本,和HTML,用法就是我们的基本格式不变我变的是其中的一些内容,这样跟好的可控性我们些组件开发的时候就可以经常用到

父组件书写

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

子组件模板书写

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

当组件渲染的时候,<slot></slot> 将会被替换为“Your Profile”。插槽内可以包含任何模板代码

1.包括HTML

<navigation-link url="/profile">
  <!-- 添加一个 Font Awesome 图标 -->
  <span class="fa fa-user"></span>
  Your Profile
</navigation-link>

2.包括其他组件

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

如果 <navigation-link>的子组件模块中 没有包含一个 <slot> 元素,则该组件起始标签和结束标签之间的任何内容都会被抛弃。

编译的作用域

父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。

例如:

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

在官网中这里的意思是user是子组件中的data对象中的值,他不可以再父组件中的作用域中显示会报错,其实也就是子组件中定义的值和父组件中的不同的作用域,所以引用会报错

后备(默认)内容

有时为一个插槽设置具体的后备 (也就是默认的) 内容是很有用的,它只会在没有提供内容的时候被渲染。

例如在一个<submit-button> 组件中他的template是:

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

那么他就可以在下<submit-button> 组件中没提供插槽的时候会有默认的Submit的值,只有在<submit-button> 组件中提供了值才会把默认值给替换掉

具名插槽

这里我们使用2.6版本的语法 v-slot

当我们需要多个插槽的时候,例如对于一个带有如下模板的 <base-layout> 组件他的tenplate为

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

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

 <base-layout> 组件他的tenplate修改后

<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 的参数的形式提供其名称:

v-slot最好是写在<template>上面

那我们给组件上添加什么内容呢?

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

现在 <template> 元素中的所有内容都将会被传入相应的插槽。任何没有被包裹在带有v-slot 的 <template> 中的内容都会被视为默认插槽的内容

然而,如果你希望更明确一些,仍然可以在一个 <template> 中包裹默认插槽的内容:

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

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

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

以前2.6以前用slot的写法是

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

  <template slot = 'default'>
    <p>A paragraph for the main content.</p>
    <p>And another one.</p>
  </template>

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

最后渲染的结果为

<div class="container">
  <header>
    <h1>Here might be a page title</h1>
  </header>
  <main>
    <p>A paragraph for the main content.</p>
    <p>And another one.</p>
  </main>
  <footer>
    <p>Here's some contact info</p>
  </footer>
</div>

注意 v-slot 只能添加在一个 <template> 上 (只有一种例外情况,等下文),这一点和已经废弃的 slot特性不同,建议都写。

作用域插槽

前面有说插槽(父组件中的innerHTML)的值是没办法访问子组件中的数据,但要是我们需要访问,我们要怎么办呢?

官网是这样讲的我来简单的解释一下

例如,设想一个带有如下模板的<current-user> 组件的tempalte为:

这里的前题是user是组件current-user中的值不是父组件中的值(这里为全局)

<span>
  <slot>{{ user.lastName }}</slot> //这里的{{user.lastName}}是当父组件没传slot过来的时候的默认值
</span>

组件插槽为:

<current-user>
  {{ user.firstName }}
</current-user>

在这里会报错,因为我们上面说过:父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。作用域中没有这个值就会报错

为了让 user 在父级的插槽内容可用,我们可以将 user 作为一个 <slot> 元素的特性绑定上去:

注意:这里一个不带 name 的 <slot> 出口会带有隐含的名字“default”

<span>
  <slot v-bind:user="user">
    {{ user.lastName }}
  </slot>
</span>

我的理解是这个<slot>上现在具有了一个可变化的属性他叫user,他的值是current-user组件中的user的值,这个值目前来说是一个对象

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

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

经过我写过后的理解就是current-user组件之后有定义一个对象user我们需要把他传对应的插槽,对应的插槽在接收通过name的值来对应相应的值,在这里<template v-slot:default="slotProps">的意思是在这里

1.用v-slot来接收,

2.名字为default(默认值)的传过来的值,

3.并把传过来的user这个值变命名为slotProps这个对象中的一个属性,

4.所以在slotProps中找到user中的firstName了

上面有说v-slot只可以写在<template>上唯一一种情况就是:当提供的内容只有默认插槽时

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

也就是<slot>上没写name,name默认为default

具名插槽的缩写

跟 v-on 和 v-bind 一样,v-slot 也有缩写,即把参数之前的所有内容 (v-slot:) 替换为字符 #。例如 v-slot:header 可以被重写为 #header

然而,和其它指令一样,该缩写只在其有参数的时候才可用。这意味着以下语法是无效的:

由于<template>中 v-slot:default=' ' 可以简写为 v-slot = ' '但是

由于下面是全部是default可以把<template>省去,把v-slot:default=' '写再父组件上

<!-- 这样会触发一个警告 -->
<current-user #="{ user }">
  {{ user.firstName }}
</current-user>

如果你希望使用缩写的话,你必须始终以明确插槽名取而代之:

<current-user #default="{ user }">
  {{ user.firstName }}
</current-user>

解构插槽prop

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

<current-user v-slot="{ user }">
  {{ user.firstName }}
</current-user>

为什么可以这样?

上文说过

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

我们父主键接到的是slotProps对象现在我们把他解构为{ user },这样我们拿到的值就是 slotProps对象中的 user的这个属性值了

总结

插槽看到这里我的理解就是对组件的高效利用,比如我现在写过的一个弹窗组件,这个弹窗的中间内容我们就可以在父组件中自己定义,这样这个组件的可利用价值就增加了,就不用说一种弹窗写一个组件

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值