插槽

145 阅读3分钟

什么是插槽

插槽就是子组件中的提供给父组件使用的一个占位符,用<slot></slot>表示,父组件可以在这个占位符中填充任何模板代码,如HTML、组件等,最后页面渲染后会将填充的模板代码替换子组件的<slot></slot>标签显示在页面上。

插槽的基础用法

父组件在使用子组件时就在子组件标签的尖括号中写要填充的模板代码。父组件可以通过组件属性传值也可以不传值给子组件。

//父组件App.vue
<template>
  <div class="father">
    <son>
      <!-- 这种写法并非嵌套child组件和son组件也不是父子组件关系 -->
      <child></child>
    </son>
    <son msg="666" title="music">
      <!-- 在子组件中插槽填充的内容 -->
      <div>少年与海,老人与海</div>
    </son>
    <son :msg="msg" :title="title">
      <!-- 在子组件中插槽填充的内容 -->
      <img src="@/assets/img/yr2.jpg"/>
    </son>
  </div>
</template>

<script>
// 1.引入子组件
import son from "@/components/son.vue";
import child from "@/components/child.vue";
export default {
  data() {
    return {
      title:"启示录",
      msg:"Gloria"
    }
  },
  components: {
    // 2.注册组件
    son,
    child
  },
};
</script>

<style scoped>
  .father {
    width: 700px;
    background-color: purple;
  }
</style>
//son.vue
//使用插槽的子组件son.vue
<template>
    <div class="son">
        <h2>我是子组件son.vue</h2>
        <h3>{{title}}----{{msg}}</h3>
        <!-- 子组件中放入一个占位符插槽 -->
        <slot></slot>
    </div>
</template>

<script>
    export default{
        props:["title","msg"]
    }
</script>

<style scoped="scoped">
    .son {
        width: 400px;
        background-color: gold;
        margin: 20px;
    }
</style>
//child.vue
//父组件App.vue的子组件child组件
<template>
  <div>
    <h3>child组件</h3>
    <p>child组件的内容</p>
  </div>
</template>

<script>
export default {

}
</script>

<style>

</style>

image.png

image.png

image.png

ps:如果子组件没有使用插槽,父组件如果需要往子组件中填充模板或者html是没法做到的。

后备内容

有时候需要给插槽设置一个具体的默认内容,当别的组件没有给填充的模板代码时,那么默认的内容就会被渲染。别的组件提供了填充的模板代码时,那么这个提供的内容将会替代默认的内容被渲染出来

image.png

image.png

插槽的使用--具名插槽和默认插槽

具名插槽其实就是给插槽取个名字,一个子组件可以放多个插槽,而且可以放在不同的地方。当父组件指定了填充模板代码的插槽名时,可以根据这个名字把内容填充到对应插槽中。

默认插槽就是指没有名字的插槽,子组件未定义名字的插槽。父组件中没有被包裹在带有 v-slot 的 <template> 中的内容都会被视为默认插槽的内容。。

父组件在向具名插槽提供内容时必须写在<template>元素中,然后在<template>元素中使用v-slot:插槽名指令来确定该模板代码插入到哪一个插槽,指令的语法糖为#插槽名

image.png

image.png

image.png

即使父组件将插槽的填充顺序打乱,只要插槽名和子组件的插槽名对应上了,就可以正确渲染到对应的插槽中。则父组件填充内容时,是可以根据这个名字把内容填充到对应插槽中的

ps:

1.父组件的填充内容指定了插槽名但是指定的插槽名在子组件中没有对应名字的插槽,那么该内容不会被填充到默认插槽中。

2.如果子组件没有默认插槽,而父组件中没有被包裹在带有 v-slot 的 <template> 中的内容就不会填充到子组件的任何一个插槽中。

3.如果子组件有多个默认插槽,而父组件所有指定到默认插槽的填充内容,将会全都填充到子组件的每个默认插槽中。

插槽的使用--作用域插槽

作用域插槽其实就是带数据的插槽,即带参数的插槽。简单的来说就是子组件提供给父组件的参数,它们接受的参数只在该插槽作用域内有效,父组件可根据子组件传过来的插槽数据来进行不同的方式展现填充的插槽内容。

作用域插槽常用于如果子组件中的某一部分的数据,父组件都会有自己的一套对该数据的不同的呈现方式,这时就需要用到作用域插槽。

首先子组件传值,需要用v-bind指令绑定一个属性用于取子组件中的数据。

<slot :user="person" name="son1"></slot>

然后父组件接收值,用v-slot:插槽名="接收数据的名字"指令设置一个名字来接收插槽传来的数据。

<template #son1="props1">
        <p style="color:white;">{{props1.user.lastname}}-----{{props1.user.firstname}}</p>
</template>
<template>
  <div class="father">
    <h1>App父组件</h1>
    <!-- 传来的数据是对象就用白色字体 -->
    <son>
      <template #son1="props1">
        <p style="color:white;">{{props1.user.lastname}}-----{{props1.user.firstname}}</p>
      </template>
    </son>
    <!-- 传来的数据是数组就用蓝色字体 -->
    <son>
      <template #son2="props2">
        <ul>
          <li style="color:blue;" v-for="(el,index) in props2.team" :key="index">{{el}}</li>
        </ul>
      </template>
    </son>
  </div>
</template>

<script>
// 1.引入子组件
import son from "@/components/son.vue";
import child from "@/components/child.vue";
export default {
  data() {
    return {
      title: "启示录",
      msg: "Gloria",
    };
  },
  components: {
    // 2.注册组件
    son,
    child,
  },
};
</script>

<style scoped>
.father {
  width: 700px;
  background-color: purple;
}
</style>

<template>
    <div class="son">
        <slot :team="tara" name="son2"></slot>
       <h4>这是son子组件</h4>
       <slot :user="person" name="son1"></slot>
    </div>
</template>

<script>
    export default{
        props:["title","msg"],
        data() {
            return {
                person:{
                    lastname:"jessica",
                    firstname:"jung"
                },
                tara:["B","Q","S","E","H","J"]
            }
        },
    }
</script>

<style scoped="scoped">
    .son {
        width: 400px;
        background-color: gold;
        margin: 20px;
    }
</style>

image.png