关于vue.js:vuejs中的默认插槽具名插槽作用域插槽三者的比较

35次阅读

共计 6457 个字符,预计需要花费 17 分钟才能阅读完成。

前言

Vue 中的插槽是一个十分弱小的性能, 在复用组件模块的时候, 针对类似的构造, 领有不通的内容时, 应用插槽就十分不便, 肯定水平上能够缩小在模板中应用大量的逻辑判断, 管制显示不通的内容

同时, 也能够让代码组织构造更加清晰, 尽管应用上是简略了, 然而插槽有些不是很好了解,不是很直观

它是让父组件能够向子组件指定地位处插入一 html 构造, 自在灵便, 也是组件间的一种通信形式

模式上有,默认插槽 , 具名插槽 还有 作用域插槽

大家在应用 element-ui 表格的时候, 尽管都晓得怎么用, 表头, 以及内容模板的渲染, 就应用了插槽, 然而往往是很迷糊的

因为被形象了的

明天就一起来学习下, 学完之后, 在看 element-ui 表格的时候, 心愿能给你带来一些启发, 下次再次应用时, 了解更上一层楼

  • 视频解说 - 见 b 站 - 默认插槽
  • 视频解说 - 见 b 站 - 具名插槽
  • 视频解说 - 见 b 站 - 作用域插槽

默认插槽

官网文档里介绍到:Vue 实现了一套内容散发的 API,这套 API 的设计灵感源自 Web Components 标准草案,将 <slot> 元素作为承载散发内容的进口

这句话不是很好了解, 换句话说, 也就是,<slot>能够充当元素标签的占位符, 能够代替在父组件援用的组件内的 html 标签内容

以如下示例所示

在 App 组件中引入 SlotBase.vue 组件

<template>
  <div id="app">
     <SlotBase
              :lists="lists">
             <p> 默认内容 </p>
     </SlotBase>
  </div>
</template>

<script>

import SlotBase from "./components/SlotBase.vue"

export default {
  name: 'App',
  components: {SlotBase},
  data() {
    return {
      lists: [
        {
          id: "001",
          title: "直播卖酒"
        },
        {
          id: "002",
          title: "直播打赏"
        },
        {
          id: "003",
          title: "直播炫富"
        }
      ]
    }
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

而在编写 SlotBase.vue 组件中, 引入 slot 标签, 如下所示

<template>
    <div class="wrap">
        <div class="list" v-for="list in lists" :key="list.id">
            {{list.title}}
            <!-- 此处引入 slot 标签 -->
            <slot></slot>
        </div>
    </div>
</template>

<script>
    export default {
        name: "SlotBase",
        props: {
            lists: {type: Array}
        },
        mounted() {console.log(this.lists);
        }
    }
</script>

<style lang="scss" scoped>
.wrap {
    display: flex;
    justify-content: center;
}
.list {
    width: 400px;
    height: 200px;
    border:1px solid red;
    margin-right: 10px;
}
</style>

在子组件内的 <slot></slot> 标签就是插槽, 代替了在父组件内的<p> 默认内容 </p>

如果你在父组件的自定义标签内, 插入了 html 模板, 在子组件没有应用slot, 那么父组件内插入的标签内容是不会被插入进去的

当初晓得插槽是什么了吧, 能够在组件标签内定义须要的内容,通过插槽退出到组件外部中

组件外部的 <slot></slot> 元素就如同一个传送门,也就是所谓的槽,它提供了内容的入口,也决定了内容的地位。组件标签中定义的内容,通过这个“传送门”就能够退出到组件外部中

插槽中的“插件”就是组件标签中的内容。

插槽中的“槽”就是在组件中的 <slot></slot> 元素, 当没有 <slot></slot> 元素的时候,就不渲染组件标签中的内容

当是默认插槽时, 咱们能够应用 template 标签给包裹起来的, 并且在下面增加 v-slot:default 属性, 这代表的是默认插槽

<template v-slot:default>
    <p> 默认内容 </p>
</template>

具名插槽

如果要将不通的内容放在不通的地位, 那么默认插槽就无奈办到了

顾名思义, 具名插槽, 就是给插槽定义一个名字, 让每个不通的模板对应着不通的名字

咱们给在父组件内的插入的模板属性上增加v-slot: 插槽名字, 而在子组件内通过增加 name 属性<slot name="插槽名字"></slot>

须要留神的是,name的值须要与 v-slot 的值要一一对应, 如果对不上的话, 那么就会达不到咱们预期的成果

如下示例代码所示: 在 App 父组件中

<template>
  <div id="app">
     <SlotBase
              :lists="lists">
             <template v-slot:default>
               <p> 默认内容 </p>
             </template>
             <template v-slot:content>
                   <p> 我是直播卖酒 -content</p>
             </template>
              <!-- <template v-slot:content2>
                   <p> 我是直播打赏 -content</p>
             </template> -->
             <!-- 能够简写成如下所示 -->
              <template #content2>
                   <p> 我是直播打赏 -content</p>
             </template>
     </SlotBase>
  </div>
</template>

<script>

import SlotBase from "./components/SlotBase.vue"

export default {
  name: 'App',
  components: {SlotBase},
  data() {
    return {
      lists: [
        {
          id: "001",
          title: "直播卖酒",
        },
        {
          id: "002",
          title: "直播打赏"
        },
        {
          id: "003",
          title: "直播炫富"
        }
      ]
    }
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

而在子组件,slotBase.vue

<template>
    <div class="wrap">
        <div class="list" v-for="list in lists" :key="list.id">
            {{list.title}}
            <!-- 此处引入 slot 标签 -->
            <slot></slot>
            <slot name="content" v-if="list.title ==' 直播卖酒 '"></slot>
            <slot name="content2" v-if="list.title ==' 直播打赏 '"></slot>
        </div>
    </div>
</template>

<script>
    export default {
        name: "SlotBase",
        props: {
            lists: {type: Array}
        },
        mounted() {console.log(this.lists);
        }
    }
</script>

<style lang="scss" scoped>
.wrap {
    display: flex;
    justify-content: center;
}
.list {
    width: 400px;
    height: 200px;
    border:1px solid red;
    margin-right: 10px;
}
</style>

下面我用了一个 v-if 条件渲染表达式, 咱们能够能够依据一些条件管制元素的显示和暗藏

下面的具名插槽, 在父组件中 v-slot:content 能够缩写为#content, 当咱们看到这种简写的时候, 晓得它也是给插槽起一个具体的名字即可

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

如果你看不懂, 那就是对简写插槽的名称有些生疏了

从下面的示例中, 咱们能够做出一些总结

  1. 具名插槽能够依据名称渲染对应的 html 标签模板内容
  2. 没有定义名称的内容会被默认插槽对立渲染
  3. 默认插槽其实也是一个具名插槽, 名称为default
  4. 父组件内插槽内容能够是模板 html 标签元素, 也能够是组件

留神

这个 v-slot 只能用在 template 标签上

旧版本写法

在父组件上应用 v-slot: 插槽名称, 这个是vue2.6.0 当前的写法, 在 vue2.6.0 之前, 能够在模板上应用slot="插槽的名称"

作用域插槽

相比于默认插槽, 具名插槽, 作用域插槽有些难以了解

如果你了解 js 中的作用域链和 Es6 中的块级作用域, 那么对于连接作用域插槽, 可能会好些

有时,让插槽内容可能拜访子组件中才有的数据, 是很有用的

插槽中内容的流动方向是从组件标签传到组件外部

作用域插槽则让作用域反向流动, 从组件外部传到组件标签内, 能够在组件标签内拜访到组件外部的变量

换而言之, 在父组件的模板中, 如何拿到子组件传递过去的数据, 而子组件 (插槽) 外部定义的数据, 如何传递到父组件当中去

也就是能够通过作用域插槽传递数据

咱们在 slotBase.vue 组件中外部定义一个数据msg

<template>
    <div class="wrap">
        <div class="list" v-for="list in lists" :key="list.id">
            {{list.title}}
            <!-- 此处引入 slot 标签 -->
            <slot></slot>
            <!--  v-bind, 自定义属性的形式向 slot 插槽传递了属性 -->
            <slot name="content" 
                  v-if="list.title ==' 直播卖酒 '":msg="msg"></slot>
            <slot name="content2" v-if="list.title ==' 直播打赏 '"></slot>
        </div>
    </div>
</template>

<script>
    export default {
        name: "SlotBase",
        props: {
            lists: {type: Array}
        },
        data() {
            return {
                // 子组件定义的数据
                msg: "itclanCoder"
            }
        },
        mounted() {console.log(this.lists);
        }
    }
</script>

<style lang="scss" scoped>
.wrap {
    display: flex;
    justify-content: center;
}
.list {
    width: 400px;
    height: 200px;
    border:1px solid red;
    margin-right: 10px;
}
</style>

在下面的代码中, 在 slot 元素上绑定了 msg 属性, 这个 attribute 被称为插槽 prop

那么在父级作用域中, 又该如何接管子组件传递过去的数据呢

v2.6.0 中应用的是 v-slot: 插槽名 ="slotProps", 其中这个slotProps 是本人任意定义的, 名字本人随便

代码如下所示:

 <template v-slot:content="slotProps">
    {{slotProps.msg}}
</template>
// 也能够缩写为 #插槽名 ="属性 Props"
 <template #content="slotProps">
    {{slotProps.msg}}
</template>

而在旧版本中, 也能够这么写

<template slot="content" slot-scope="slotProps">
        {{slotProps.msg}}
</template>

新版本的写法与 vue2.6.0 以下的版本不能混写, 留神, 这种废除的语法, 在 vue3.0 中不会呈现了的

所以还是用最新的写法吧, 然而一些老的 vue2.0 我的项目, 旧版本的写法, 要看的懂的

以上就是默认插槽, 具名插槽, 作用域插槽的应用, 插槽是一个十分弱小的性能, 在组件的复用时, 对于复用构造和精简代码十分有用

如果大家有做过那种后盾 cms 管理系统,针对很多不同品种的各种表单弹窗, 而表单弹窗内, 有时要依据后端返回的接口 props 去显示指定的内容

这时候, 插槽就十分有用了

独占默认插槽的缩写

当被提供的内容只有默认插槽时, 组件的标签才能够被当做插槽的模板来应用

咱们能够间接把 v-slot 间接用在组件上

<CurrentUser v-slot:default="slotProps">
          <p>{{slotProps.user}}</p>
</CurrentUser>

还能够在简化一下。就像假设未指明的内容对应默认插槽一样,不带参数的 v-slot 被假设对应默认插槽

<CurrentUser v-slot="slotProps">
          <p>{{slotProps.user}}</p>
</CurrentUser>

须要留神的是, 以下写法是不能够的, 当 v-slot 用在自定义标签组件上, 不能缩写

Named slots must use '<template>' on a custom element

<CurrentUser #slotProps>
          <p>{{slotProps.user}}</p>
</CurrentUser>

::: tip 留神
默认插槽的缩写语法不能和具名插槽混用, 因为它会导致作用域不明确

<!-- 有效,会导致正告 -->
<current-user v-slot="slotProps">
  {{slotProps.user.firstName}}
  <template v-slot:other="otherSlotProps">
    slotProps is NOT available here
  </template>
</current-user>

:::
只有呈现多个插槽, 所有的插槽应用残缺的基于 template 的语法
也就是说,v-slot用在 template 标签上

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

  <template v-slot:other="otherSlotProps">
    ...
  </template>
</current-user>

总结

以上本节的内容, 插槽是一个十分弱小的性能, 默认插槽在子组件外部应用 <slot></slot> 进行占位, 而在父组件内, 应用 html 标签, 或者组件

如果子组件应用了多个插槽,那么就应用 具名插槽 对每个插槽进行辨别, 子组件内的 <slot name="插槽名称"></slot>, 而在父组件中, 应用template 标签

<template v-slot: 插槽名称 ></template>, 其中 v-slot 有简写 # 插槽名称, 能够应用在具体的标签上, 然而当有多个插槽时, 只能用在template 标签上

当父组件想要拿到子组件中的数据, 子组件外部又是如何把外部数据传递到内部组件中去的呢, 在子组件外部是通过在 slot 插槽 props 传递到父父组件当中去的

而在父组件当中, 通过 v-slot: 插槽名 ="slotProps" 进行接管, 这个 slotProps 是一个汇合对象, 接管了子组件 props

这就是作用域插槽, 它也是父子组件传递数据的一种形式

原文出处 -Vuejs 中的默认插槽、具名插槽, 作用域插槽

正文完
 0