Vue中的Slots你真的用明白了吗?

242 阅读3分钟

前言

Slots对于大多前端开发业务的时候,可能想到得更多的就是官方提出“挖坑”的概念,哪里需要补哪里;在一些B端产品中,页面有大量重复样式组件的情况下,可以进行v-slot来结合组件化开发,提高我们开发效率。

插槽 Slots简介

Vue官网中介绍:在某些场景中,我们可能想要为子组件传递一些模板片段,让子组件在它们的组件中渲染这些片段。(其实就相当于占位符,它在组件中给你的HTML模板占了一个位置,让你来传入一些东西。)

插槽类型和基本使用

  • 默认插槽(匿名插槽,可以在父组件放入想要填补子组件插槽的内容)
<template> 
<div class="child-box"> 
<p>我是子组件</p> 
<!-- 插槽 -->
<slot></slot> 
</div> 
</template>

<!-- 接收 prop 的具名插槽 --> 
<template> 
<img alt="Vue logo" src="./assets/logo.png" />
<child> 
<div>我是插槽位置的内容</div> 
</child> 
</template>
  • 具名插槽
子组件声明:
<div class="container"> 
<header>
<slot name="header"></slot>
</header> 
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer> 
</div>

父组件使用:
<BaseLayout> 
<template #header>
<h1>Here might be a page title</h1> </template> 
<template #default>
<p>A paragraph for the main content.</p> 
</template> 
<template #footer>
<p>Here's some contact info</p> 
</template> 
</BaseLayout>
  • 作用域插槽(可以类似于组件传递 props,向一个插槽的出口上传递 attributes
<!-- <MyComponent> 的模板 --> 
<div>
<slot :text="greetingMessage" :count="1"></slot> 
</div>

<MyComponent v-slot="slotProps"> 
{{ slotProps.text }} {{ slotProps.count }} 
</MyComponent>

插槽Slots的实际应用

🙋Demo源码在此
B端产品可能都会有如下增删改查的大量页面,CV开发可能会是大多数开发者的选择,这同样也是一个比较高效的做法。但是但是但是💢!当产品要求改某一样式的时候,比如说标题的字体或者大小,按钮和页码的位置调整等,那可能有十几页面甚至上百张页面,这时候就得花费大量时间去做重复的事情。
截屏2023-02-04 15.45.29.png 1. 创建对应的组件
UI提供设计图之后,可以先总结设计图来进行分析,进行页面拆分分类。这里我根据该页面需求创建了头部,表单,表格和弹窗的对应组件。

截屏2023-02-04 16.01.19.png 2.v-slot UI组件化

  • Header组件
    通过props接收了父组件的标题和图标(也可通过作用域进行声明接收),具名插槽声明了页面内容的位置,并写好相应的样式。
<template>
  <div class="box shadow" ref="queryRef">
    <div class="unit_header">
      <div>
        <!-- 接收父组件(主页面)传递的图标和标题 -->
        <img :src="titleImg" alt="" />&nbsp;<span>{{ title }}</span>
      </div>
    </div>
    <slot name="content"></slot>
  </div>
</template>

<style scoped lang="scss">
.box {
  width: 100%;
  padding: 0 20px;
  height: 100%;
  box-sizing: border-box;
  ......
}
</style>

  • Form组件
    通过具名插槽确定表单和表单相应按钮的位置,并且在此组件中定义好了插槽中的表单里的样式。
<template>
  <div class="box_content">
    <div class="box_from" ref="queryRef">
      <slot name="form"> </slot>
    </div>
    <div class="search-btn-style">
      <div class="btns-style">
        <div style="float: left">
          <slot name="searchBtnLeft"></slot>
        </div>
        <div style="float: right">
          <slot name="searchBtnRight"></slot>
        </div>
      </div>
    </div>
  </div>
</template>

<style lang="scss" scoped>
.box_content {
  margin: 20px 0 10px 20px;
  // 定义在父组件中插入的内容的样式
  ::v-deep(.el-form) {
    display: grid;
    column-gap: 60px;
    row-gap: 10px;
    grid-template-columns: repeat(3, auto);
    .el-form-item {
      width: 420px;

      .el-button {
        width: 104px;
        height: 32px;
        border-radius: 4px;
      }
    }
  }
......

 
}
</style>

🙋Demo源码在此
3.父组件引用
在父组件中仅仅只是作为声明和引用,样式的整体修改只需要在组件中进行整改即可。

<HeaderLayout title="综合查询" :titleImg="state.titleImg">
   <template v-slot:content>
     <FormLayout>
       <template v-slot:form>
         <el-form
           ref="queryRef"
           :model="state.queryParams"
           :inline="true"
           label-width="auto"
         >
          ......
         </el-form>
       </template>
       <template v-slot:searchBtnLeft>
         <el-button @click="openOrClose" v-show="!isOpen">
           <span>展开&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
           <el-icon>
             <ArrowDownBold />
           </el-icon>
         </el-button>
         <el-button @click="openOrClose" v-show="isOpen">
           <span>收起&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
           <el-icon>
             <ArrowUpBold />
           </el-icon>
         </el-button>
       </template>
       <template v-slot:searchBtnRight>
         <div class="btns-style">
           <el-button type="primary" @click="obj.handleQuery">查询</el-button>
           <el-button @click="obj.resetQuery(proxy)">重置</el-button>
         </div>
         ......
         </div>
       </template>
     </FormLayout>
     <TableLayout>
       <template v-slot:tableBtnLeft>
        ......
       </template>
       <template v-slot:table>
         ......
       </template>
       <template v-slot:pagination>
         ......
       </template>
     </TableLayout>
     <el-dialog v-model="state.open" width="500px" append-to-body>
       <DialogLayout></DialogLayout>
     </el-dialog>
   </template>
 </HeaderLayout>

总结

Demo仅仅是针对于样式修改的组件化来使用,通过Slots能够灵活地在父组件的插入内容,达到提高统一页面样式结构修改的效率。在一些点击的交互的功能和逻辑业务等,同样也可以通过Slots去根据自己的需求业务进行扩展使用。