插槽有几种方法

230 阅读2分钟

插槽的方式一共有三种

默认插槽

具名插槽

自定义属性插槽

插槽的使用步骤:

  1. 定义组件时,在template中用slot 定义插槽
  1. 使用组件时,通过<组件> 传入结构 </组件>

父传子

  • prop: 从父组件向子组件传递自定义数据
  • 插槽: 从父组件向子组件传递自定义结构
  • 作用域插槽:  数据 + 自定义结构

image.png

默认插槽

概念:

如果外面不给传,想给个默认显示内容

口诀

slot夹着内容默认显示内容,如果不给插槽slot传东西,则使用夹着的内容在原地显示

   <slot>默认内容</slot>

具名插槽

概念:

当一个组件内有2处以上需要外部传入标签的地方

要求:

v-slot一般用跟template标签使用(template是h5新出来内容模板元素,不会渲染到页面上,一般被vue解析内容标签)

App.vue

<template>
  <div id="container">
    <div id="app">
      <h3>案例:折叠面板</h3>
      <Pannel>
        <template v-slot:title>
          <h4>将进酒</h4>
        </template>
        <template v-slot:content>
          <img src="./assets/cat.gif" alt="">
          <span>我是内容</span>
        </template>
          
      </Pannel>
      <Pannel>
        <template #title>
          <span style="color:red">我是标题</span>
        </template>
        <template #content>
          <p>君不见黄河之水天上来,奔流到海不复回。</p>

          <p>君不见高堂明镜悲白发,朝如青丝暮成雪。</p>

          <p>人生得意须尽欢,莫使金樽空对月。</p>

          <p>天生我材必有用,千金散尽还复来。</p>
        </template>
      </Pannel>
    </div>
  </div>
</template>

<script>
import Pannel from "../src/components/02/Pannel.vue";
export default {
  components: {
    Pannel,
  },
};
</script>

Pannel.vue

<template>
  <div>
    <!-- 按钮标题 -->
    <div class="title">
      <slot name="title"></slot>
      <span class="btn" @click="isShow = !isShow">
        {{ isShow ? "收起" : "展开" }}
      </span>
    </div>
    <!-- 下拉内容 -->
    <div class="container" v-show="isShow">
      <slot name="content"></slot>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      isShow: false,
    };
  },
};
</script>

<style scoped>
h3 {
  text-align: center;
}

.title {
  display: flex;
  justify-content: space-between;
  align-items: center;
  border: 1px solid #ccc;
  padding: 0 1em;
}

.title h4 {
  line-height: 2;
  margin: 0;
}

.container {
  border: 1px solid #ccc;
  padding: 0 1em;
}

.btn {
  /* 鼠标改成手的形状 */
  cursor: pointer;
}

img {
  width: 50%;
}
</style>

效果如下

 解析

v-slot: 可以简化为 # 使用

总结

slot的name属性起插槽名.使用组件时,template配合#插槽名传入具体标签

作用域插槽

概念:

子组件里值,在给插槽赋值时在父组件环境下使用

eg:

默认内容在子组件中,但是父亲在给插槽传值,想要改变插槽显示的默认内容

口诀
  1. 子组件,在slot上绑定属性和子组件内的值
  2. 使用组件,传入自定义标签,用template和v-slot="自定义变量名"
  3.  scope变量名自动绑定slot上所有属性和值
App.vue

<template>
  <div id="container">
    <div id="app">
      <h3>案例:折叠面板</h3>
      <Pannel>
        <!-- 需求:插槽时,使用组件内变量 -->
        <template v-slot="scope">
          <p>{{scope.row.defaultTwo}}</p>
        </template>
        <template v-slot:content>
          <img src="./assets/cat.gif" alt="">
          <span>我是内容</span>
        </template>
          
      </Pannel>
      <Pannel>
        <template #title>
          <span style="color:red">我是标题</span>
        </template>
        <template #content>
          <p>君不见黄河之水天上来,奔流到海不复回。</p>

          <p>君不见高堂明镜悲白发,朝如青丝暮成雪。</p>

          <p>人生得意须尽欢,莫使金樽空对月。</p>

          <p>天生我材必有用,千金散尽还复来。</p>
        </template>
      </Pannel>
    </div>
  </div>
</template>

<script>
import Pannel from "../src/components/02/Pannel.vue";
export default {
  components: {
    Pannel,
  },
};
</script>

Pannel.vue

<template>
  <div>
    <!-- 按钮标题 -->
    <div class="title">
      <h4>将进酒</h4>
      <span class="btn" @click="isShow = !isShow">
        {{ isShow ? "收起" : "展开" }}
      </span>
    </div>
    <!-- 下拉内容 -->
    <div class="container" v-show="isShow">
     <slot :row="defaultObj">{{ defaultObj.defaultOne }}</slot>
    </div>
  </div>
</template>

<script>
// 目标: 作用域插槽
// 场景: 使用插槽, 使用组件内的变量
// 1. slot标签, 自定义属性和内变量关联
// 2. 使用组件, template配合v-slot="变量名"
// 变量名会收集slot身上属性和值形成对象
export default {
  data() {
    return {
      isShow: false,
      defaultObj: {
        defaultOne: "天生我材必有用",
        defaultTwo: "千金散尽还复来"
      }
    };
  },
};
</script>

效果

​编辑

 总结

组件内变量绑定在slot上,然后使用组件v-slot="变量",变量上就会绑定slot身上属性和值

使用场景:

 封装一个表格组件,在表格组件内循环产生单元格

App.vue

<template>
  <div>
    <MyTable :arr="list"></MyTable>
    <MyTable :arr="list">
        <!-- scope: {row: obj} -->
       <template v-slot="scope">
            <a :href="scope.row.headImgUrl">{{ scope.row.headImgUrl }}</a>
       </template>
    </MyTable>
    <MyTable :arr="list">
       <template v-slot="scope">
            <img style="width: 100px;" :src="scope.row.headImgUrl" alt="">
       </template>
    </MyTable>
  </div>
</template>

<script>
import MyTable from "./components/02/Pannel.vue";
export default {
  components: {
    MyTable,
  },
  data() {
    return {
      list: [
        {
          name: "小红同学",
          age: 18,
          headImgUrl:
            "http://yun.itheima.com/Upload/./Images/20210303/603f2d2153241.jpg",
        },
        {
          name: "小黑同学",
          age: 25,
          headImgUrl:
            "http://yun.itheima.com/Upload/./Images/20210304/6040b101a18ef.jpg",
        },
        {
          name: "小兰同学",
          age: 21,
          headImgUrl:
            "http://yun.itheima.com/Upload/./Images/20210302/603e0142e535f.jpg",
        },
      ],
    };
  },
};
</script>

<style>
</style>

Pannel.vue

<template>
  <div>
      <table border="1">
          <thead>
              <tr>
                  <th>序号</th>
                  <th>姓名</th>
                  <th>年龄</th>
                  <th>头像</th>
              </tr>
          </thead>
          <tbody>
              <tr v-for="(obj, index) in arr" :key="index">
                  <td>{{ index + 1 }}</td>
                  <td>{{ obj.name }}</td>
                  <td>{{ obj.age }}</td>
                  <td>
                      <slot :row="obj">
                          <!-- 默认值给上,如果使用组件不自定义标签显示默认文字 -->
                          {{ obj.headImgUrl}}
                      </slot>
                  </td>
              </tr>
          </tbody>
      </table>
  </div>
</template>

<script>
export default {
    props: {
        arr: Array
    }
}
</script>

效果

 总结

插槽可以自定义标签,作用域插槽可以把组件内的值取出来自定义内容