Typescript + vue3 二次封装el-table问题?

封装的table:

<template>
  <div class="app-table">
    <slot name="header" class="app-table-header"></slot>
    <el-table
      ref="customTable"
      :data="tableData"
      class="app-table-content"
      stripe
      :tooltip-effect="tooltipEffect"
      :highlight-current-row="highlightCurrentRow"
      @selection-change="selectionChange"
      @select="selectRows"
      @select-all="selectAll"
      @row-click="selectRowClick"
      :default-expand-all="expandAll"
      v-bind="expandObj"
      :current-row-key="currentRowKey"
      :size="tableSize"
      v-loading="loading"
    >
      <template #empty>
        <div class="no-data" v-show="isEmptyData">
          <div class="empty-icon"></div>
          <div class="empty-text">暂无数据</div>
        </div>
      </template>
      <el-table-column
        v-for="column in columns"
        :key="column.prop"
        :prop="column.prop"
        :label="column.label"
        :width="column.width"
        :min-width="column.minWidth"
        :show-overflow-tooltip="column.showOverflowTooltip"
        :fixed="column.fixed"
        :sortable="column.sortable"
        :align="column.align"
      >
        <!--自定义列头-->
        <template #header v-if="column.slotHeader">
          <slot :name="column.slotHeader" :column="column"></slot>
        </template>
        <template #default="scope">
          <!--自定义列内容-->
          <span v-if="column.slotName">
            <slot
              :name="column.slotName"
              :row="scope.row"
              :$index="scope.$index"
              :$count="tableData.length"
              :$pagination="pagination"
            ></slot>
          </span>
          <!--格式化内容-->
          <span v-else-if="column.formatter">{{ column.formatter(scope.row, column) }}</span>
          <span v-else>
            {{ initColValue(scope.row, column.prop) }}
          </span>
        </template>
      </el-table-column>
    </el-table>
    <el-pagination
      v-if="showPage && total"
      :small="pagination.small"
      :total="total"
      :current-page="pagination.currentPage"
      :page-sizes="pagination.pageSizes"
      :page-size="pagination.limit"
      class="app-table-pagination"
      :layout="pagination.layout"
      @current-change="pageChange"
      @size-change="pageSizeSelect"
    />
  </div>
</template>

<script lang="ts" setup>
import { computed, ComputedRef, reactive, ref, watch } from 'vue';
interface TableProps {
  columns: Table.Column[]; // 每列的配置项
  options?: Table.Options;
  columnTypes?: string; //  额外表格列,selection/index/expand
  service: Function; // 获取table data 方法,需要返回promise
  datas: Array<string>;
  beforeSearch?: (params: any) => Promise<any>; // 查询table参数处理
  afterSearch?: (res: any) => any; // 查询table 结果处理
  rowKey?: [String, Function];
  expandAll?: Boolean;
  expandRowKeys?: [];
  showPage?: Boolean;
  pageOpt: { small: boolean; limit: number; pageSizes: number; layout: string };
  highlightCurrentRow?: Boolean;
  currentRowKey?: [String, Number];
  tooltipEffect?: String;
  rowClick?: Function;
  tableSize?: String;
  selectRow?: [];
  immediateSearch?: Boolean;
}
// 接受父组件参数,配置默认值
const props = defineProps<TableProps>();
// const props = withDefaults(defineProps<TableProps>(), {});
interface EmitEvent {
  (e: 'pageChange', current: number): void;
  (e: 'pageSizeChange', size: number): void;
  (e: 'search'): void; // 重置当前页 重新检索
  (e: 'select-row', row: any): void;
  (e: 'selection-change', selection: any): void; // 当选择项发生变化时会触发该事件
  (e: 'row-click', rows: any): void; // 当某一行被点击时会触发该事件
  (e: 'cell-click', row: any, column: any, cell: any, event: Event): void; // 当某个单元格被点击时会触发该事件
  (e: 'select-all', row: any): void;
  (e: 'size-change', pageSize: number): void; // pageSize事件
  (e: 'current-change', currentPage: number): void; // currentPage按钮组事件
}
const emit = defineEmits<EmitEvent>();
let tableData: any = reactive([]);
const isEmptyData = ref<boolean>(false);
const loading = ref<boolean>(false);
let total = ref<number>(0);
const customTable = ref(null);
let rowKeys = props.expandRowKeys ? [...props.expandRowKeys] : [];
// 设置option默认值,如果传入自定义的配置则合并option配置项
const _options: ComputedRef<Table.Options> = computed(() => {
  const option = {
    stripe: false,
    tooltipEffect: 'dark',
    showHeader: true,
    showPagination: false,
    rowStyle: () => 'cursor:pointer', // 行样式
  };
  return Object.assign(option, props?.options);
});
const pagination = {
  small: false,
  currentPage: 1,
  limit: 10,
  pageSizes: [10, 20, 50, 100],
  layout: 'total, sizes, prev, pager, next, jumper',
};
watch(
  () => props.service,
  () => search()
);
watch(
  () => props.datas,
  () => {
    pagination.limit = 10;
    pagination.currentPage = 1;
    getTableDatas();
  },
  { deep: true }
);
const expandObj = computed(() => {
  if (props.rowKey) {
    return {
      'row-key': props.rowKey,
      'expand-row-keys': rowKeys,
    };
  }
  return {};
});
const isBackEnd = computed(() => {
  return !!props.service;
});

const pageChange = (current: number) => {
  pagination.currentPage = current;
  emit('pageChange', current);
  getTableDatas();
};
const pageSizeSelect = (size: number) => {
  pagination.limit = size;
  emit('pageSizeChange', size);

  search();
};
// 重置当前页 重新检索
const search = (): void => {
  pagination.currentPage = 1;
  getTableDatas();
};
// 根据当前条件检索
const getTableDatas = (): void => {
  // 组装参数
  const { limit, currentPage } = pagination;
  if (!isBackEnd.value) {
    tableData = props.datas.slice((currentPage - 1) * limit, limit * currentPage);
    total.value = props.datas.length;
    return;
  }
  const data = {
    pageSize: limit,
    pageNum: currentPage, // 当前页page数
  };
  // this.tableData = [];
  loading.value = true;
  // 查询前处理参数
  const params = props.beforeSearch!(data);
  props
    .service(params)
    .then((res: any) => {
      console.log('数据----', res);
      loading.value = false;
      // 重新设置expandRowKeys 不然不会默认展开
      if (props.rowKey && rowKeys) {
        rowKeys = rowKeys.slice(0);
      }
      if (total.value === 0) {
        isEmptyData.value = true;
      } else {
        isEmptyData.value = false;
      }
    })
    .catch((err: any) => {
      loading.value = false;
      console.log(err);
      // this.$message.error(err.errorMsg || '获取列表数据出错!');
    });
};
const initColValue = (row: any, prop: any) => {
  let result = row;
  if (prop && prop.indexOf('.') !== -1) {
    prop.split('.').forEach((vv: any) => {
      result = result[vv];
    });
  } else {
    result = result[prop];
  }
  return result;
};
const selectionChange = (selection: any) => {
  emit('selection-change', selection);
};
const selectRowClick = (rows: any) => {
  emit('row-click', rows);
};
const selectRows = (row: any) => {
  emit('select-row', row);
};
const selectAll = (row: any) => {
  emit('select-all', row);
};

getTableDatas();
</script>

因为我这个封装是将数据和分页都是在组件中处理,只暴露出service即可
页面中使用:

<app-table
      :columns="tableIaasColumn"
      :service="tableServer"
      :limit="6"
      :beforeSearch="handleParams"
    />
<script lang="ts" setup>
import { reactive } from 'vue';
import { getIaasList, IaasSearchForm } from '@/pages/admin/service/capacity';
const tableIaasColumn = [
  { prop: 'name', label: '业务名称', align: 'center' },
  { prop: 'businessName', label: '业务名称', align: 'center' },
  { prop: 'type', label: '需求种类', align: 'center' },
  { prop: 'createDate', label: '创建时间', align: 'center' },
  {
    width: '250',
    label: '操作',
    align: 'center',
    buttons: [
      { name: '查看', type: 'primary', command: 'look' },
      { name: '下载', type: 'success', command: 'down' },
      { name: '删除', type: 'danger', command: 'delete' },
    ],
  },
] as Table.Column[];

const iaasSearchForm = reactive<IaasSearchForm>({
  name: '',
  businessName: '',
  currentPage: 1,
  pageSize: 10,
});

type TableServer = () => void;
let tableServer: TableServer = async () => await getIaasList(iaasSearchForm);

const handleParams = (params: any) => {
  return {
    ...params,
    ...params.value,
  };
};
</script>

但是能打印出数据,但是也面没渲染,这是哪里写错了(我也是最近学typescript,搞得很懵逼),有用过typescript大佬帮忙看看怎么写就对了,感谢。

页面上我是这样获取的:

type TableServer = () => void;
let tableServer: TableServer = async () => await getIaasList(iaasSearchForm);

const handleParams = (params: any) => {
  return {
    ...params,
    ...params.value,
  };
};
阅读 2.7k
1 个回答

el-table 需要的的数据 tableData,按照下面代码实现的应该能出来,你的代码没看到给 tableData 赋 service 返回的值呀

<template>
  <div class="app-table">
    <el-table
      :data="tableData"
    >
    </el-table>
  </div>
</template>

<script lang="ts" setup>
import { computed, ComputedRef, reactive, ref, watch } from 'vue';
const tableData = ref([]);
props
    .service(params)
    .then((res: any) => {
      tableData.value = res.data || []
    })

</script>
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题