ant design vue二次封装一个table+pagination组件

396 阅读1分钟

封装思想封装思想

1.二次封装的组件所有数据由父组件传过来,只是作为容器与具体的业务数据不挂钩

2.尽可能的适应大多数的场景,少数场景可拓展

【1 如何解决外部组件给内部组件的传递参数问题:

如果选择defineProps的话,参数太多,写出的代码非常冗杂

  • 因此利用$attrs来传,他可以拿到props没传的属性
【2 处理插槽传递的问题
  • 如何处理多个插槽的传递

  • 并且要传了哪些插槽用哪些v-for遍历+$slots属性 ($slots可拿到一个对象,对象中的属性就是外部传过来的插槽)

  • image.png

    • 然后根据这些属性动态生成封装组件中的<template>
    • 再通过<slot>映射出来
【3 因为要保证二次封装组件的可拓展性,可能组件有时候要暴露一些方法,所以要解决如何接收方法的问题
  • ref获取自己封装的组件的实例再由defineExpose()暴露出去

原来的代码是这样的:

<a-table
        :columns="columns"
        :data-source="meetingRoomResult"
        :pagination="false"
      >

        <template v-slot:bodyCell="{ column, record }">

          <!-- 预订详情 -->

          <template v-if="column.dataIndex === 'isBooked'">

            <MeetingRoomBookingModal :meetingRoomNameFirst="record.name" />

          </template>

          <!-- 创建时间 -->

          <template v-if="column.dataIndex === 'createTime'">

            <div>{{ formatTime(record.createTime) }}</div>

          </template>

          <!-- 更新时间 -->

          <template v-if="column.dataIndex === 'updateTime'">

            <div>{{ formatTime(record.updateTime) }}</div>

          </template>

          <!-- 操作 -->

          <template v-else-if="column.dataIndex === 'operate'">

            <a-popconfirm

              title="你确定要删除吗"

              cancel-text="No"

              ok-text="Yes"

              @confirm="confirm(record.id)"

              @cancel="removeMeetingRoom"

            >

              <a-tag color="red">删除</a-tag>

            </a-popconfirm>

            <!-- <div > -->

            <a-tag color="blue" @click="showModal(record.id)">更新</a-tag>

            <!-- </div> -->

          </template>

        </template>

      </a-table>

  


<div class="pagination">

        <a-pagination

          v-model:current="pageNo"

          :total="(totalCount / pageSize) * 10"

          show-less-items

        />

      </div>

现在是这样的:

这是二次封装的组件

<!-- 对列表和分页器组件的二次封装 -->
<template>
  <div>
    <a-table v-bind="$attrs" ref="tableRef">
        <!-- 这里#[value]是在动态指定插槽名,slotData是要传给对应插槽的数据 -->
        <template v-for="(key,value) in $slots" #[value]="slotData">  
             <!-- slot作为一个插槽出口来接收外部组件传来的插槽 -->
            <slot :name="value" v-bind="slotData || {}"></slot>
        </template>
    </a-table>
    <a-pagination show-less-items v-bind="$attrs" class="pagination" ref="paginationRef"></a-pagination>
  </div>
</template>

<script setup lang="ts">
import { Pagination, Table } from 'ant-design-vue';
import { ref } from 'vue';
const tableRef = ref<InstanceType<typeof Table>>()
const paginationRef = ref<InstanceType<typeof Pagination>>()
defineExpose({
    tableRef,
    paginationRef
})

</script>

这是用组件的地方

     <PageList
        :total="(totalCount / pageSize) * 10"
        v-model:current="pageNo"
        :columns="columns"
        :data-source="meetingRoomResult"
        :pagination="false"
      >
        <template v-slot:bodyCell="{ column, record }">
          <!-- 预订详情 -->
          <template v-if="column.dataIndex === 'isBooked'">
            <MeetingRoomBookingModal :meetingRoomNameFirst="record.name" />
          </template>
          <!-- 创建时间 -->
          <template v-if="column.dataIndex === 'createTime'">
            <div>{{ formatTime(record.createTime) }}</div>
          </template>
          <!-- 更新时间 -->
          <template v-if="column.dataIndex === 'updateTime'">
            <div>{{ formatTime(record.updateTime) }}</div>
          </template>
          <!-- 操作 -->
          <template v-else-if="column.dataIndex === 'operate'">
            <a-popconfirm
              title="你确定要删除吗"
              cancel-text="No"
              ok-text="Yes"
              @confirm="confirm(record.id)"
              @cancel="removeMeetingRoom"
            >
              <a-tag color="red">删除</a-tag>
            </a-popconfirm>
            <!-- <div > -->
            <a-tag color="blue" @click="showModal(record.id)">更新</a-tag>
            <!-- </div> -->
          </template>
        </template>
      </PageList>