vxe-table封装vue组件(开箱即用)

<template>
  <div class=”table-box”>
    <div style=”padding: 0 15px” v-if=”!showAnimate”>
      <vxe-form ref=”formRef” v-bind=”searchParams” :data=”model”> </vxe-form>
    </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=”40″ v-if=”checkbox” :fixed=”‘left'”></vxe-column>
          <vxe-column type=”expand” width=”40″ v-if=”expand” :fixed=”‘left'”>
            <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 class=”pagination-container flx-j-end”>
          <vxe-pager
            v-model:current-page=”current”
            v-model:page-size=”size”
            style=”padding-right: 10px”
            :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,
  // 表单属性配置
  formOptions: {
    type: Array,
    default: () => ([])
  },
  // 分页大小选项
  pageSizes: {
    type: Array,
    default: () => [10, 20, 30, 50, 100]
  },
  // 虚拟滚动是否开启
  enabled : {
    type: Boolean,
    default: true
  }
});
const emits = defineEmits([‘reset’,’error’])
const colSetting = ref(props.columns)
const tableRef = ref()
const model = ref({ …props.searchParams })
const formRef = ref(null)
const showAnimate = ref(true)
const current = ref(1)
const size = ref(10)
const total = ref(0)
const tableData = ref([])
const searchParams = ref({
  items: [
    …props.formOptions,
    …(props.formOptions.some(item => item.isActionButtons) ? [] : [{
      align: “right”,
       itemRender: {
        name: “VxeButtonGroup”,
        options: [
          {
            type: “submit”,
            content: “查询”,
            status: “primary”,
            onClick: () => {
              console.log(“查询”, model.value)
              search()
            }
          },
          {
            type: “reset”,
            content: “重置”,
            onClick: () => reset()
          },
        ],
      },
    }])
  ],
});
// 动态虚拟滚动配置
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 search = () => {
  getTableData()
}
const reset = () => {
  emits(‘reset’)
  current.value = 1
  tableRef.value.clearCheckboxRow();
  tableRef.value.clearRadioRow();
  selectLists.value = [];
  selectIdLists.value = [];
  selectList.value = [];
  setTimeout(() => {
    getTableData();
  }, 0);
}
const getTableData = () => {
  // const loadingInstance = ElLoading.service({
  //   text: ‘加载中…’
  // })
  model.value = 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 openColSetting = () => {
  tableRef.value.openCustom()
};
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 exportEvent = () =>{
   tableRef.value.openExport()
}
defineExpose({
  getTableData,
  tableRef,
  selectLists,
  selectIdLists,
  selectList
})
</script>
<style scoped lang=”scss”>
@import ‘./style.scss’;
</style>

发表回复

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