vue3对element的table封装带分页

5 篇文章 0 订阅
1 篇文章 0 订阅
文章介绍了如何使用Vue.js和ElementUI的el-table组件构建一个可配置的表格,支持自定义列类型、样式、操作以及响应式功能,如多选、排序、合并单元格和分页。
摘要由CSDN通过智能技术生成

template

<template>
  <div :class="config?.style ? 'table-demo-fix' : 'table-demo'">
    <div class="tableTitle" v-if='config?.headerName'>{{config.headerName}}</div>
    <el-table
      :class="config?.headerName?'':'ocTable'"
      :data="data"
      :border="setBorder"
      v-bind="$attrs"
      row-key="id"
      stripe
      :show-summary="config?.showSummary"
      :height="config?.height"
      style="width: 100%"
      v-loading="config?.loading"
      @selection-change="onSelectionChange"
      :span-method="objectSpanMethod"
      :row-class-name="tableRowClassName"
      :summary-method="getSummaries"
    >
      <el-table-column type="selection" :reserve-selection="true" width="40" v-if="config?.isSelection" />
      <el-table-column type="index" label="序号" width="60" v-if="config?.isSerialNo" :align="'center'" />
      <el-table-column
        v-for="(item, index) in header"
        :key="index"
        show-overflow-tooltip
        :prop="item.key"
        :width="item.colWidth"
        :label="item.title"
        :align="item.align || 'left'"
      >
        <template v-slot="scope">
          <template v-if="item.type === 'image'">
            <el-image
              :style="{ width: `${item.width}px`, height: `${item.height}px` }"
              :src="scope.row[item.key]"
              :zoom-rate="1.2"
              :preview-src-list="[scope.row[item.key]]"
              preview-teleported
              fit="cover"
            />
          </template>
          <template v-else-if="item.type === 'time'">
            {{ formatDateTime(scope.row[item.key]) }}
          </template>
          <template v-else-if="item.type === 'select'">
            <span v-if="!item.tagType">{{ filterName(item.options, scope.row[item.key], item.tag1, item.tag2) }}</span>
            <el-tag v-else :type="item.tagType">{{ filterName(item.options, scope.row[item.key], item.tag1, item.tag2) }}</el-tag>
          </template>
          <!-- 自定义内容显示 type=='scope' -->
          <template v-else-if="item.type === 'scope'">
            <slot name="tableSlot" :tableSlotobj="scope.row" :key="item.key"></slot>
          </template>
          <!-- 添加第二个自定义插槽 -->
          <template v-else-if="item.type === 'tabScope'">
            <slot name="table" :tableSlotobj="scope.row" :key="item.key"></slot>
          </template>
          <!-- 自定义操作按钮 type=='btnScope' -->
          <template v-else-if="item.type === 'btnScope'">
            <slot name="btnSlot" :btnScopeObj="scope.row" :key="item.key" :item="item" :index="scope.$index"></slot>
          </template>
          <template v-else>
            {{ scope.row[item.key] }}
          </template>
        </template>
      </el-table-column>
      <el-table-column
        label="操作"
        :width="config?.operate?.width"
        v-if="config?.operate?.isOperate"
        fixed="right"
        :align="config?.operate?.align || 'center'"
        class-name="toolClass"
      >
        <template #default="{ row }">
          <template v-for="(item, index) in config?.operate?.btns" :key="index">
            <el-button :type="item.type" text @click="btnClick(item, row)">
              {{ item.title }}
            </el-button>
          </template>
        </template>
      </el-table-column>
      <template #empty>
        <el-empty description="暂无数据" />
      </template>
    </el-table>
    <!-- config.total不写的时候 不显示分页 -->
    <el-pagination
      v-if="config?.total != null"
      small
      :current-page="state.page.pageNum"
      :page-size="state.page.pageSize"
      :pager-count="5"
      :page-sizes="[10, 20, 30]"
      :total="config.total"
      layout="total, sizes, prev, pager, next, jumper"
      background
      @size-change="onHandleSizeChange"
      @current-change="onHandleCurrentChange"
    >
    </el-pagination>
  </div>
</template>

script

<script setup lang="ts" name="netxTable">
import '/@/theme/tableTool.scss'
import { formatDateTime } from '/@/utils/formatTime'
// 定义父组件传过来的值
const props = defineProps({
  // 列表内容
  data: {
    type: Array<EmptyObjectType>,
    default: () => [],
  },
  // 表头内容
  header: {
    type: Array<EmptyObjectType>,
    default: () => [],
  },
  // 配置项
  config: {
    type: Object,
    default: () => {},
  },
})

// 定义变量内容
const state = reactive({
  page: {
    pageNum: 1,
    pageSize: props.config?.params?.Count | 10,
  },
})

const emit = defineEmits(['toolEvent', 'selectChange', 'pageChange', 'changePage','objectSpanMethod','getSummaries','tableRowClassName'])
// 监听分页变化
watch(
  () => state.page,
  () => {
    let { pageNum, pageSize }: any = state.page
    let Start = (pageNum - 1) * pageSize
    let Count = pageSize
    emit('changePage', { Start, Count })
  },
  { deep: true}
)
// 设置边框显示/隐藏
const setBorder = computed(() => {
  return props.config?.isBorder ? true : false
})
// 条数改变
const onHandleSizeChange = (val: number) => {
  state.page.pageSize = val
}
// 页数改变
const onHandleCurrentChange = (val: number) => {
  state.page.pageNum = val
}
// 选中
const onSelectionChange = (val: EmptyObjectType[]) => {
  emit('selectChange', val)
}
//处理下拉回写数据
const filterName = (data: Array<EmptyObjectType>, row: String | Number | boolean, tag1: string, tag2: string) => {
  let name = []
  if (tag1 && tag2) {
    name = data.filter((i: any) => {
      return row == i[tag1]
    })
    if (name.length) {
      return name[0][tag2]
    } else {
      return ''
    }
  } else {
    name = data.filter((i: any) => {
      return i.key == row
    })
    if (name.length) {
      return name[0].value
    } else {
      return ''
    }
  }
}
//按钮事件
const btnClick = (item: any, row: any) => {
  emit('toolEvent', item, row)
}
// 表格合并单元格 
const objectSpanMethod = ({ row, column, rowIndex, columnIndex }:any)=> {
  emit('objectSpanMethod',{ row, column, rowIndex, columnIndex } )
}
// 合并行或列的计算方法合计
const getSummaries = (param:any) => {
  emit('getSummaries',param )
  return props.config?.summaryList
}
// table row更改颜色
const tableRowClassName = ({row, rowIndex}:any) => {
  emit('tableRowClassName',{ row,rowIndex,} )
}
</script>

style

<style scoped lang="scss">
.table-demo {
  height: calc(100% - 70px);
  background: #fff;
  :deep(.el-table--fit) {
    height: calc(100% - 40px) !important;
    .el-table__inner-wrapper {
      min-height: calc(100% - 10px) !important;
    }
  }
  .el-pagination {
    background-color: #fff;
  }
  .ocTable {
    margin-top: 10px;
  }
  .el-pagination {
    float: right;
  }
}
.tableTitle{
    width: 100%;
    height: 40px;
    line-height: 40px;
    font-size: 18px;
    text-align: center;
    font-weight: bold;
    border: 1px solid rgb(235,238,245);
    border-bottom: none;
    color: rgb(144,147,153);
    margin-top: 8px;
  }
.table-demo-fix {
  height: calc(100%);
  background: #fff;
  .el-pagination {
    background-color: #fff;
  }
  .ocTable {
    margin-top: 10px;
  }
  .el-pagination {
    float: right;
  }
}
</style>

父组件的使用

<template>
  <div>
    <Table ref="tableRef" v-bind="state.tableData" @toolEvent="toolEvent" @changePage="changePage">
      <template #tableSlot="tableSlot">
        {{tableSlot.tableSlotobj.IsValidation ? tableSlot.tableSlotobj.IsCharges ? '直接放行' : '收取费用' : ''}}
      </template>
      <template #table="tableSlot">
        {{tableSlot.tableSlotobj.IsValidation ? tableSlot.tableSlotobj.IsCharges ? '' : tableSlot.tableSlotobj.IsRules ? '固定金额' : '阶梯金额' : ''}}
      </template>
    </Table>
  </div>
</template>

<script lang="ts" setup>
const Table = defineAsyncComponent(() => import('/@/components/table/index.vue'))
const tableRef = ref()
const state = reactive({
  tableData: {
    // 列表数据(必传)
    data: [],
    // 表头内容(必传,注意格式)
    header: [
      { key: 'Name', colWidth: '', title: '名称', type: 'text' },
      { key: 'IsValidation', colWidth: '', title: '是否验证', type: 'select',options: [{key: true,value:'是'},{key:false,value:'否'}] },
      { key: 'IsCharges', colWidth: '', title: '是否收费', type: 'scope'},
      { key: 'IsRules', colWidth: '', title: '规则', type: 'tabScope',options: [{key: null,value:''},{key: true,value:'固定金额'},{key:false,value:'阶梯金额'}] },
      { key: 'CreateTime', colWidth: '160', title: '创建时间', type: 'time' },
      { key: 'ModifiedTime', colWidth: '160', title: '最后一次修改时间', type: 'time' },
    ],
    // 配置项(必传)
    config: {
      total: 0, // 列表总数
      params: {
        Count: 10, //结束页
        Start: 0, //开始页
      } as any,
      loading: false, // loading 加载
      isBorder: true, // 是否显示表格边框
      isSerialNo: true, // 是否显示表格序号
      isSelection: false, // 是否显示表格多选
      style: false,
      operate: {
        isOperate: true, // 是否显示表格操作栏
        btns: [
          {
            title: '编辑',
            type: 'primary',
          },
          {
            title: '删除',
            type: 'danger',
          },
        ],
      },
    },
  },
})
const toolEvent = (item: any, row: any) => {
  if (item.title == '编辑') {
    onEdit(row)
  } else {
    onDelete(row)
  }
}
const onEdit = (val: Object) => {
  console.log("%c 🇸🇦: onEdit -> val ", "font-size:16px;background-color:#99b8fc;color:white;", val)
}
const onDelete = (row: any) => {
  console.log("%c 🌽: onDelete -> row ", "font-size:16px;background-color:#d15a51;color:white;", row)
}
</script>
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值