Vue3+TS项目封装一个公共的el-table组件二次封装

发布于:2024-09-18 ⋅ 阅读:(13) ⋅ 点赞:(0)

前言

支持动态传入列,列内容可以指定插槽,指定格式化显示

样式没太写,主要分享基础功能封装

效果

Table组件代码BaseTable.vue

<template>
  <el-table :data="data" border>
    <template v-for="col in columns" :key="col.prop">
      <el-table-column :prop="col.prop" :label="col.label" :width="col.width" show-overflow-tooltip>
        <template #default="{ row }">
          <slot v-if="col.slot" :name="col.slot"></slot>
          <!-- 因为这个内容不是通过表格的prop直接绑定的,所以表格自带的溢出省略号失效,自己写下 -->
          <div v-else class="text-overflow">{{ getFormatter(col, row[col.prop]) }}</div>
        </template>
      </el-table-column>
    </template>
  </el-table>
  <br>
  <template v-if="isShowPage">
    <el-pagination v-model:currentPage="currentPage1" v-model:page-size="pageSize1" :page-sizes="[10, 20, 30, 40]"
      background layout="total, sizes, prev, pager, next, jumper" :total="totalSize" @size-change="sizeChange"
      @current-change="currentChange" />
  </template>
</template>
<script lang="ts" setup>
import { computed, ref } from 'vue';

export interface BaseTableConfig {
  data: any[];
  columns: TableColumn[];
  current?: number;
  pageSize?: number;
  totalSize?: number;
  [key: string]: any;
}
export interface TableColumn {
  prop?: string;
  label: string;
  slot?: string;
  width?: number;
  formatter?: Function;
  [key: string]: any;
}
const emit = defineEmits(['update:pageSize', 'update:currentPage', 'pageChange'])
const props = defineProps({
  data: {
    type: Array,
    default: () => ([])
  },
  columns: {
    type: Array<any>,
    default: () => ([])
  },
  currentPage: {
    type: Number,
    default: 1,
  },
  pageSize: {
    type: Number,
    default: 10,
  },
  totalSize: {
    type: Number,
    default: 0,
  },
  isShowPage: {
    type: Boolean,
    default: true,
  }
});
const currentPage1 = ref(props.currentPage);
const pageSize1 = ref(props.pageSize);
const getFormatter = (col: any, value: any) => {
  if (col.formatter) {
    return col.formatter(value);
  }
  return value;
}
const sizeChange = (val: number) => {
  emit('update:pageSize', val);
  emit('pageChange');
}
const currentChange = (val: number) => {
  emit('update:currentPage', val);
  emit('pageChange');
}
</script>
<style scoped>
.text-overflow {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
</style>

页面中使用组件

<template>
  <div>总条数:{{ tbConfig.totalSize }};当前页:{{ tbConfig.current }};每页条数:{{ tbConfig.pageSize }}</div>

  <BaseTable :data="tbConfig.data" :columns="tbConfig.columns" v-model:currentPage="tbConfig.current"
    v-model:pageSize="tbConfig.pageSize" :totalSize="tbConfig.totalSize" @pageChange="pageClick">
    <template #avatar="{ row }">
      这一列用插槽自定义内容{{ row?.avatar }}
    </template>
    <template #op>
      <el-button type="danger">删除</el-button>
    </template>
  </BaseTable>
</template>
<script lang="ts" setup>
import { reactive } from 'vue';
import { BaseTableConfig, TableColumn } from './BaseTable.vue';
import BaseTable from './BaseTable.vue';

const tbConfig: BaseTableConfig = reactive({
  data: [
    { id: 1, name: 'Ahsh', avatar: 'img1.png', ifKey: true },
    { id: 2, name: 'Rjjds', avatar: 'img2.png', ifKey: false },
    { id: 3, name: 'Ukkd特别长长长长长长长长长长的名字', avatar: 'img3.png', ifKey: true },
  ],
  columns: <TableColumn[]>[
    { prop: 'id', label: '序号', width: 100 },
    { prop: 'name', label: '名称', width: 200 },
    { prop: 'avatar', label: '图标', slot: 'avatar', width: 200 },
    { prop: 'ifKey', label: '是否开放', formatter: formatBoolean },
    { label: '操作', slot: 'op' },
  ],
  current: 1,
  pageSize: 10,
  totalSize: 0,
});

function formatBoolean(val: Boolean) {
  return val ? '是' : '否';
}

function pageClick() {
  // TODO监听到当前页或者每页条数变化,重新查询列表
  console.log('get-data');
}
</script>
<style scoped></style>