Vue学习---插槽篇

Vue插槽

    • 1. 初步了解插槽
    • 2. 插槽的分类
      • 2.1 默认插槽
      • 2.2 具名插槽
      • 2.3 作用域插槽

1. 初步了解插槽

什么是插槽?


插槽就是子组件提供给父组件使用的一个占位符,可以通俗理解为“占坑作用”。有了该占位符,父组件可以在该占位符中填充任何模板,不仅限于传递数据,也可以填充如HTML、组件、template模板、标签等。填充后,内容替换子组件的标签

为什么要使用插槽?
在组件通信中(详情见文章:Vue组件学习、组件通信),我们了解到组件之间如何传递数据。那父组件在复用子组件的时候除了想给子组件传递数据,还想更改子组件的内容和样式时,怎么办呢?
一般来说,父组件是没办法更改子组件的内容和样式的,总结就是“你可以用我但是不可以更改我”。
就像买车一样 不能自己去决定车的配置、外观、性能、尺寸,这些都是厂家自己设计好然后批量生产的 ,大家买下都是一样的。

如果你真的想更改子组件,那就使用插槽。
插槽的作用就是使得父组件可以改造子组件,让父组件提供内容,在子组件中展示

使用场景:

  • 使用插槽让用户拓展组件,更好地复用组件和对其做定制化处理。
  • 当一个子组件被父组件复用时,或许在不同情况下需要被更改,此时如果去重写组件是 一件不明智的事情,此时通过slot插槽向子组件内部指定位置传递内容,是一个更好的选择。
  • 在布局组件、表格列、下拉框、弹框显示内容中常用。

插槽的作用:
让父组件向子组件指定位置插入html结构,也是一种组件间的通信方式。

2. 插槽的分类

2.1 默认插槽

案例场景:以下是一个组件的复用(一个蓝色的div即是一个组件),该组件在页面中复用了3次,我想对某一个组件实现私人定制,比如,美食组件我只想放一张图片,电影组件中我想放一个视频,如何做?
Vue学习---插槽篇_第1张图片
由上方效果变成下面这样的:
Vue学习---插槽篇_第2张图片
制定子组件Category.vue:
这是没有使用插槽的情况,组件不能实现定制化:

<template>
  <div class="category">
    <h3>{{title}}h3>    
    <ul>
      <li v-for="(item,index) in listData" :key="index">{{item}}li>
    ul>
  div>
template>
<script>
  export default{
    name:"Category",
    // 接收父组件传过来的值
    props:['listData','title']
  }
script>
<style>
  .category{
    background-color: skyblue;
    width: 200px;
    height: 300px;
  }
  h3{
    text-align: center;
    background-color: orange;
  }
style>

在App.vue中使用Category.vue:

<template>
  <div id="app">
    <!-- 复用子组件 静态传输标题,动态传输数组-->
   <Category title="美食" :listData="foods" />
   <Category title="书籍" :listData="books"/>
   <Category title="电影" :listData="films"/>
  </div>
</template>

<script scope="this api replaced by slot-scope in 2.5.0+">
import Category from './components/Category.vue';
export default {
  name: 'App',
  components: {
    Category,
  },
  data(){
    return{
      // 定义数据
      foods:['火锅','重庆火锅','小龙虾','牛排'],
      books:['语文','数学','英语','化学'],
      films:['重庆森林','七龙珠','犬夜叉','心灵捕手'],
    }
  }
}
</script>

<style>
#app {
  display: flex;
  justify-content: space-around;
}
</style>

以上复用只能出现第一个页面效果,见下图:
Vue学习---插槽篇_第3张图片
如果不使用作用域插槽,仅在App.vue更改组件中内容,子组件是不会将内容渲染的
在App.vue中更改子组件内容,此时子组件中无插槽!!!

   <Category title="美食" >
    <img src="@/assets/hotpot.jpg" alt="">
  </Category>
   <Category title="书籍" :listData="books"/>
   <Category title="电影" :listData="films"/>

子组件无法渲染在父组件中更改的页面结构,如下图:
Vue学习---插槽篇_第4张图片
下面使用默认插槽:
在子组件Category.vue中定义一个默认插槽:

<template>
  <div class="category">
    <h3>{{title}}h3>
    
    <slot>默认值,当父组件没有出现时,我会出现slot>
  div>
template>
<script>
  export default{
    name:"Category",
    // 接收父组件传过来的值
    props:['title']
  }
script>
<style>
  .category{
    background-color: skyblue;
    width: 200px;
    height: 300px;
  }
  h3{
    text-align: center;
    background-color: orange;
  }
style>

App.vue:

<template>
  <div id="app">
    
   <Category title="美食" >
    <img src="@/assets/hotpot.jpg" alt="">
  Category>

   
   <Category title="书籍">
    <ul>
      <li v-for="(item,index) in books" :key="index">{{item}}li>
    ul>
  Category>

   
   <Category title="电影">
    <video src="@/assets/1.mp4" controls>video>
  Category>
  div>
template>

<script scope="this api replaced by slot-scope in 2.5.0+">
import Category from './components/Category.vue';
export default {
  name: 'App',
  components: {
    Category,
  },
  data(){
    return{
      // 定义数据
      foods:['火锅','重庆火锅','小龙虾','牛排'],
      books:['语文','数学','英语','化学'],
      films:['重庆森林','七龙珠','犬夜叉','心灵捕手'],
    }
  }
}
script>

<style>
#app {
  display: flex;
  justify-content: space-around;
}
img{
  width: 100%;
}
video{
  width: 100%;
}
style>

注意:对样式的定义,可以定义在父组件也可以定义在子组件。
区别:

  • 定义在父组件,结构先编译好样式再传给子组件;
  • 定义在子组件中,结构传给子组件,再由子组件编译。
<style>
img{
  width: 100%;
}
video{
  width: 100%;
}
style>

2.2 具名插槽

上诉案例中,提高需求,我想在分割线下添加一个跳转链接(分割线以上的都是默认插槽区域),如何做?
Vue学习---插槽篇_第5张图片
使用默认插槽和使用作用域插槽的区别:
Vue学习---插槽篇_第6张图片

具名插槽就是把父组件想要更改的元素插在子组件的某个位置上,并且只接受对应名字的更改元素,而默认插槽则会把父组件的更改元素全盘接收。
使用vue2.6的新语法时,建议使用template模板包裹元素

Category.vue

<template>
  <div class="category">
    <h3>{{title}}h3>
    
    <slot>默认值,当父组件没有出现时,我会出现slot>
    -------------------------
    
    <slot name="link">slot>
    
  div>
template>

App.vue

<template>
  <div id="app">
    
    <Category title="美食" >
    <img src="@/assets/hotpot.jpg" alt="">
     
    
    <template >
      <div class="foot"><a href="">更多美食a>div>
    template>
  Category>

   
   <Category title="书籍">
    <ul>
      <li v-for="(item,index) in books" :key="index">{{item}}li>
    ul>
    
    
    <div class="foot" slot="link" >
      <a href="https://www.taobao.com/" >去淘宝a>
      <a href="https://www.taobao.com/" >去京东a>
    div>
    
    <br>
    
  Category>

   
   <Category title="电影">
    <video src="@/assets/1.mp4" controls>video>
    
    
    <template v-slot:link>
      <div class="foot">
        <a href="">经典a>
        <a href="">热门a>
        <a href="">推荐a>
      div>
      <h4>欢迎前来观影h4>
    template>
  Category>
  div>
template>

<script scope="this api replaced by slot-scope in 2.5.0+">
import Category from './components/Category.vue';
export default {
  name: 'App',
  components: {
    Category,
  },
  data(){
    return{
      // 定义数据
      foods:['火锅','重庆火锅','小龙虾','牛排'],
      books:['语文','数学','英语','化学'],
      films:['重庆森林','七龙珠','犬夜叉','心灵捕手'],
    }
  }
}
script>

<style >
#app,.foot{
  display: flex;
  justify-content: space-around;
}
img{
  width: 100%;
}
video{
  width: 100%;
}
h4{
  text-align: center;
}
style>

2.3 作用域插槽

理解: 数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。
案例:
Vue学习---插槽篇_第7张图片
父组件:

<Category title="游戏">

      <template scope="row">
        
        <ul>
          <li v-for="(g, index) in row.games" :key="index">{{ g }}li>
        ul>
      template>
    Category>
    <Category title="游戏">
    
      <template scope="row">
        <ol>
          <li style="color: red" v-for="(g, index) in row.games" :key="index">
            {{ g }}
          li>
        ol>
      template>
    Category>
    <Category title="游戏">
    
      <template scope="row">
        <h4 v-for="(g, index) in row.games" :key="index">{{ g }}h4>
      template>
    Category>

子组件中:

   <h3>{{title}}分类h3>
   
   <slot :games='games'>默认内容slot>
   <script>
    export default {
      props: ['title'],
      data() {
        return {
          games: ['红色警戒', '穿越火线', '劲舞团', '超级玛丽']
        }
      }
    }
script>

作用域插槽可以看成数据的方向流动,有子组件传给父组件
注意:作用域插槽的使用一定要使用template模板

你可能感兴趣的:(Vue,vue.js,学习,javascript)