前言

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中的默认插槽、具名插槽,作用域插槽