• Vue组件化开发-插槽的使用详解


    Vue组件化-插槽

    1.插槽基本介绍

    在开发中,我们会经常封装一个个可复用的组件

    • 前面我们会通过props传递给组件一些数据,让组件来进行展示;
    • 但是为了让这个组件具备更强的通用性,我们不能将组件中的内容限制为固定的div、span等等这些元素;
    • 比如某种情况下我们使用组件,希望组件显示的是一个按钮,某种情况下我们使用组件希望显示的是一张图片
    • 我们应该让使用者可以决定某一块区域到底存放什么内容和元素

    举个栗子:假如我们定制一个通用的导航组件 - NavBar

    • 这个组件分成三块区域:左边-中间-右边,每块区域的内容是不固定;
    • 左边区域可能显示一个菜单图标,也可能显示一个返回按钮,可能什么都不显示;
    • 中间区域可能显示一个搜索框,也可能是一个列表,也可能是一个标题,等等;
    • 右边可能是一个文字,也可能是一个图标,也可能什么都不显示;

    在这里插入图片描述

    这个时候我们就可以来定义插槽slot

    • 插槽的使用过程其实是抽取共性、预留不同
    • 我们会将共同的元素、内容依然在组件内进行封装
    • 同时会将不同的元素使用slot作为占位,让外部决定到底显示什么样的元素;

    如何使用slot呢?

    • Vue中将 元素作为承载分发内容的出口
    • 在封装组件中,使用特殊的元素就可以为封装组件开启一个插槽
    • 该插槽插入什么内容取决于父组件如何使用;

    在这里插入图片描述


    2.插槽基本使用

    例如我们定义如下一个子组件

    <template>
      <div class="show-message">
        <h2>{{ title }}h2>
        <p>{{ content }}p>
      div>
    template>
    
    <script>
      export default {
        props: {
          title: {
            type: String,
            default: ""
          },
          content: {
            type: String,
            default: ""
          }
        }
      }
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    我们在父组件中使用这个子组件的时候, 虽然可以改变内容, 但是h2元素和p元素是固定的

    <template>
      <div class="app">
    		
        <show-message title="哈哈哈哈" content="我是内容1">show-message>
        <show-message title="呵呵呵呵" content="我是内容2">show-message>
        <show-message title="嘿嘿嘿嘿" content="我是内容3">show-message>
      div>
    template>
    
    <script>
      import ShowMessage from './ShowMessage.vue'
    
      export default {
        components: {
          ShowMessage
        }
      }
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    但是我们确实想要更改元素的话, 就需要使用到插槽, 例如: 将p元素改为使用其他元素进行展示

    • 在子组件中插入插槽
    <template>
      <div class="show-message">
        <h2>{{ title }}h2>
        
        
        <slot>slot>
      div>
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 插槽部分想要展示什么内容由父元素进行决定, 如果插槽没有 插入东西, 那么这个插槽会被忽略
    <template>
      <div class="app">
        
        <show-message title="哈哈哈哈">
          <p>我是内容1p>
        show-message>
    
    		
        <show-message title="呵呵呵呵">
          <button>我是内容2button>
        show-message>
        
    		
        <show-message title="嘿嘿嘿嘿">
          <h3>我是内容3h3>
        show-message>
      div>
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    效果如下 :

    在这里插入图片描述


    3.插槽默认内容

    有时候我们希望在使用插槽时,如果没有插入对应的内容,那么我们需要显示一个默认的内容

    • 当然这个默认的内容只会在没有提供插入的内容时,才会显示;

    我们可以在标签中设置一个默认内容

    <template>
      <div class="show-message">
        <h2>{{ title }}h2>
    
        
        <slot>
          <p>我是默认内容p>
        slot>
      div>
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    当我们没有使用插槽时, 没有插入对象内容时, 就会展示默认内容

    <template>
      <div class="app">
        
        <show-message title="嘿嘿嘿嘿">show-message>
      div>
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    效果如下:

    在这里插入图片描述


    4.多个插槽效果

    还是通过一个简单案例分析, 例如我们做一个导航栏, 有如下一个子组件在父组件中展示

    • 由于左, 中, 右三个部分都是不顾定的, 所以我们使用三个插槽, 并给插槽默认值
    <template>
      <div class="nav-bar">
        <div class="left">
          <slot>leftslot>
        div>
    
        <div class="content">
          <slot>contentslot>
        div>
    
        <div class="right">
          <slot>rightslot>
        div>
      div>
    template>
    
    <script>
      export default {}
    script>
    
    <style scoped>
      .nav-bar {
        display: flex;
        height: 44px;
        line-height: 44px;
        text-align: center;
      }
    
      .left {
        width: 70px;
        background-color: aquamarine;
      }
    
      .content {
        flex: 1;
        background-color: skyblue;
      }
    
      .right {
        width: 70px;
        background-color: pink;
      }
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 默认情况下, 展示效果如图:

    在这里插入图片描述

    • 此时我们想要在父组件中, 分别对三个插槽插入内容, 此时组件中含有多个插槽,我们插入多个内容时是什么效果?
    <template>
      <div class="app">
        <nav-bar>
          <button>返回button>
          <span>内容span>
          <a href="#">登录a>
        nav-bar>
      div>
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 我们会发现默认情况下每个插槽都会获取到我们插入的内容来显示;

    在这里插入图片描述

    此时我们发现, 上面操作是无法完成我们的需求, 此时就需要具名插槽

    5.具名插槽使用

    事实上,我们希望达到的效果是插槽对应内容的显示,这个时候我们就可以使用具名插槽

    • 具名插槽顾名思义就是给插槽起一个名字, 元素有一个特殊的 attribute:name
    • 一个不带 name 的slot,会带有隐含的名字 default

    也就是说, 我们可以给每个插槽都取上一个名字, 如下 :

    <template>
      <div class="nav-bar">
        <div class="left">
          <slot name="left">leftslot>
        div>
    
        <div class="content">
          <slot name="content">contentslot>
        div>
    
        <div class="right">
          <slot name="right">rightslot>
        div>
      div>
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在父组件中使用的时候, 需要包裹一个