vxe-table封装vue组件(开箱即用)-灵活度更高,适合产品过于定制化

<template>
  <div class=”table-box”>
    <div>
      <div style=”padding: 0 15px” v-if=”!showAnimate”>
        <vxe-form ref=”formRef”>
          <slot name=”form-items”></slot>
          <vxe-form-item>
            <vxe-button-group>
              <vxe-button type=”submit” status=”primary” @click=”search”>查询</vxe-button>
              <vxe-button type=”reset” @click=”reset”>重置</vxe-button>
            </vxe-button-group>
          </vxe-form-item>
        </vxe-form>
      </div>
    </div>
    <div class=”table-container”>
      <div class=”flex flx-j-between” style=”margin-bottom: 10px”>
        <div>
          <slot name=”header-button-le” />
        </div>
        <div>
          <slot name=”header-button-ri” />
          <slot name=”toolButton”>
            <el-tooltip :content=”showAnimate ? ‘展开’ : ‘收起'” placement=”top”>
              <el-button :icon=”Filter” @click=”showSearch” />
            </el-tooltip>
            <el-tooltip :content=”‘刷新'” placement=”top”>
              <el-button :icon=”Refresh” @click=”search” />
            </el-tooltip>
            <el-tooltip :content=”‘列设置'” placement=”top”>
              <el-button :icon=”Operation” @click=”openColSetting” />
            </el-tooltip>
            <el-button :icon=”Download” @click=”exportEvent” v-show=”DownloadBarShow” />
          </slot>
        </div>
      </div>
      <div class=”table-wrapper”>
        <vxe-table
          ref=”tableRef”
          :id=”id”
          :data=”tableData”
          :border=”border”
          v-bind=”tableProps”
          height=”89%”
          @checkbox-all=”selectChange”
          @checkbox-change=”selectChange”
          @radio-change=”radioChange”
          :show-footer=”showFooter”
          :show-header-overflow=”showHeaderOverflow”
          :show-footer-overflow=”showFooterOverflow”
          :footer-data=”footerData”
          :row-config=”{
            useKey: true,
            keyField: Key,
            isHover: true,
            isCurrent: true,
            resizable: true,
          }”
          :column-config=”{ useKey: true, resizable: true }”
          :custom-config=”customConfig”
          :tooltip-config=”tooltipConfig”
          :export-config=”downLoadType”
          :scroll-y=”virtualConfig.y”
          :scroll-x=”virtualConfig.x”
        >
          <vxe-column type=”radio” width=”60″ v-if=”radio” :fixed=”‘left'”></vxe-column>
          <vxe-column type=”checkbox” width=”60″ v-if=”checkbox” :fixed=”‘left'”></vxe-column>
          <vxe-column type=”expand” width=”60″ v-if=”expand”>
            <template #content=”{ row }”>
              <div>
                <slot name=”expand” :row=”row”></slot>
              </div>
            </template>
          </vxe-column>
          <vxe-column type=”seq” width=”70″ v-if=”seq” :fixed=”‘left'”></vxe-column>
          <template v-for=”item in colSetting” :key=”item[Key]”>
            <vxe-column
              v-bind=”item”
              :align=”item.align ?? ‘left'”
              :show-overflow=”item.showOverflow ?? true”
              :show-header-overflow=”item.showHeaderOverflow ?? false”
              :show-footer-overflow=”item.showFooterOverflow ?? false”
              :title-prefix=”item[‘title-prefix’]”
              :title-suffix=”item[‘title-suffix’]”
              row-resize
            >
              <template #header=”scope”>
                <slot v-if=”item.header” :scope=”scope” :name=”item.header” />
                <span v-else>{{ scope.column.title }}</span>
              </template>
              <template #default=”scope”>
                <slot v-if=”item.slot” :scope=”scope” :name=”item.slot” />
                <div v-else>
                  {{ formatData(scope.row, item.field) }}
                </div>
              </template>
            </vxe-column>
          </template>
          <!– 空数据时显示图片 –>
          <template #empty>
            <div class=”emptyStyle”>
              <img
                src=”@/assets/images/notData.png”
                style=”width: 200px; opacity: 0.6″
                alt=”暂无数据”
              />
              <div style=”margin-top: 10px; color: #909399″>暂无数据</div>
            </div>
          </template>
        </vxe-table>
        <div>
          <vxe-pager
            style=”padding-right: 10px”
            v-model:current-page=”current”
            v-model:page-size=”size”
            :page-size=”size”
            :total=”total”
            :layouts=”[‘Total’, ‘Sizes’, ‘PrevPage’, ‘Number’, ‘NextPage’, ‘Jump’, ‘PageCount’]”
            :page-sizes=”pageSizes”
            @page-change=”handlePageChange”
          >
            <template #pageCount=”{ pageCount }”>
              <span>共{{ pageCount }}页</span>
            </template>
          </vxe-pager>
        </div>
      </div>
    </div>
  </div>
</template>
<script setup lang=”js”>
import { onMounted, ref, computed, reactive   } from ‘vue’;
import { ElLoading, ElMessage } from ‘element-plus’;
import { Filter, Operation, Refresh, Download } from ‘@element-plus/icons-vue’;
import { cloneDeep } from ‘lodash-es’;
const props = defineProps({
  // 表格id
  id: {
    type: String,
    required: true,
  },
  // 查询参数对象
  searchParams: {
    type: Object,
    default: () => ({})
  },
  // 查询参数对象自定义
  apiParams: {
    type: Object,
    default: () => ({})
  },
  // 是否显示序号列
  seq: {
    type: Boolean,
    default: false
  },
  // 是否显示单选列
  radio: {
    type: Boolean,
    default: false
  },
  // 是否显示多选列
  checkbox: {
    type: Boolean,
    default: true
  },
  // 是否显示展开行
  expand: {
    type: Boolean,
    default: false
  },
  // 是否显示表格边框
  border: {
    type: Boolean,
    default: false
  },
  // 获取数据的API函数
  apiName: {
    type: Function,
    required: true,
  },
  // 表格行的唯一标识字段名
  Key: {
    type: String,
    default: ‘id’
  },
  // 导出文件类型
  downLoadType: {
    type: [String, Object],
    default: () => ({ type: ‘xlsx’ })
  },
  // 是否显示导出按钮
  DownloadBarShow: {
    type: Boolean,
    default: false
  },
  // 是否显示表尾
  showFooter: {
    type: Boolean,
    default: false
  },
  // 表尾内容是否溢出显示
  showFooterOverflow: {
    type: Boolean,
    default: true
  },
  // 表头内容是否溢出显示
  showHeaderOverflow: {
    type: Boolean,
    default: true
  },
  // 表尾数据
  footerData: {
    type: Array,
    default: () => ([])
  },
  // 提示配置
  tooltipConfig: {
    type: Object,
    default: () => ({})
  },
  // 列配置
  columns: Array,
  // 表格属性配置
  tableProps: Object,
  // 分页大小选项
  pageSizes: {
    type: Array,
    default: () => [10, 20, 30, 50, 100]
  },
  // 虚拟滚动是否开启
  enabled : {
    type: Boolean,
    default: true
  }
});
const emits = defineEmits([‘reset’,’error’]);
const loading = ref(false)
const colSetting = ref(props.columns);
const tableRef = ref();
const formRef = ref(null);
const showAnimate = ref(true);
const current = ref(1);
const size = ref(10);
const total = ref(0);
const tableData = ref([]);
// 动态虚拟滚动配置
const virtualConfig = computed(() => ({
  y: {
    enabled:  props.enabled,
    gt: 80,
    scrollY: {
      mode: ‘wheel’ // 推荐配置:滚轮模式更流畅
    }
  },
  x: {
    enabled: tableData.value.some(row => {
      try {
        return (Object.keys(row).length > 8 || JSON.stringify(row).length > 300 )&& props.enabled
      } catch {
        return false
      }
    }),
    gt: 5,
    scrollX: {
      mode: ‘wheel’
    }
  }
}))
// 其余方法保持不变
const formatData = (row, field) => {
  return field && row[field] !== undefined ? row[field] : ‘-‘;
};
const selectIdLists = ref([]);
const selectLists = ref([]);
const selectChange = () => {
  const records = tableRef.value?.getCheckboxRecords() || [];
  selectLists.value = records;
  selectIdLists.value = records.map((i) => { return i[props.Key] });
};
const selectList = ref([]);
const radioChange = ({ row }) => {
  selectList.value = row;
};
const showSearch = () => {
  showAnimate.value = !showAnimate.value;
  // formRef.value.toggleCollapse();
};
const model = ref({})
const search = () => {
  getTableData();
};
const reset = () => {
  emits(‘reset’);
  current.value = 1
  tableRef.value.clearCheckboxRow();
  tableRef.value.clearRadioRow();
  selectLists.value = [];
  selectIdLists.value = [];
  selectList.value = [];
  setTimeout(() => {
    getTableData();
    console.log(‘model.value’, model.value);
  }, 0);
};
const getTableData = () => {
  // const loadingInstance = ElLoading.service({
  //   text: ‘加载中…’
  // })
  model.value = cloneDeep(props.searchParams)
  const apiParams = cloneDeep(props.apiParams)
  const query = {
    …model.value,
    …apiParams,
    current: current.value,
    size: size.value
  }
  if (!props.apiName) return;
  props.apiName(current.value,size.value,Object.assign({},query))
    .then(({ data:res }) => {
      // loadingInstance.close()
      tableData.value = res.data.records || []
      total.value = res.data.total || 0
    })
    .catch((err) => {
      // loadingInstance.close()
      emits(‘error’, err)
    })
}
const handleSizeChange = (val) => {
  size.value = val;
};
const handleCurrentChange = (val) => {
  current.value = val;
};
const handlePageChange = ({ currentPage, pageSize }) => {
  handleSizeChange(pageSize)
  handleCurrentChange(currentPage)
  getTableData();
}
onMounted(() => {
  getTableData();
});
const findCustomSetting = (id) => {
  return new Promise(resolve => {
    setTimeout(() => {
      try {
        if (sessionStorage.getItem(id)) {
          resolve(JSON.parse(sessionStorage.getItem(id) || ”))
          // ElMessage.success(‘异步还原用户个性化数据成功’)
        } else {
          resolve({})
        }
      } catch (e) {
        resolve({})
      }
    }, 300)
  })
}
const saveCustomSetting = (id, storeData) => {
  return new Promise(resolve => {
    setTimeout(() => {
      sessionStorage.setItem(id, JSON.stringify(storeData))
      ElMessage.success(‘保存用户个性化数据成功’)
      resolve()
    }, 200)
  })
}
const customConfig = reactive({
  storage: true,
  restoreStore ({ id }) {
    return findCustomSetting(id)
  },
  updateStore ({ id, storeData }) {
    return saveCustomSetting(id, storeData)
  }
})
const openColSetting = () => {
  tableRef.value.openCustom();
};
const exportEvent = () => {
  tableRef.value.openExport();
};
defineExpose({
  getTableData,
  tableRef,
  selectLists,
  selectIdLists,
  selectList
});
</script>
<style scoped lang=”scss”>
@import ‘./style.scss’;
</style>

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注