Skip to content

组件文档

表格分页组件

参数

参数名类型默认值说明
totalNumber0总条数
pageNumber1初始化加载页数
limitNumber20每页的记录行数
pageSizesArray[10, 20, 30, 50]可供选择的每页的行数
pagerCountNumber5设置最大页码按钮数
layoutStringtotal, sizes, prev, pager, next, jumper组件布局,子组件名用逗号分隔
backgroundBooleantrue是否为分页按钮添加背景色
autoScrollBooleantrue自动滚动到顶部
hiddenBooleanfalse是否显示分页
pagination事件函数分页事件

案例

html
<template>
  <div>
    <pagination
      :total="total"
      v-model:page="currentPage"
      v-model:limit="limit"
      v-model:pageSizes="pageSizes"
      :layout="pagelayout"
      :background="backgroundpage"
      :autoScroll="autoScrollpage"
      :hidden="hiddenpage"
      @pagination="changePage"
    >
    </pagination>
  </div>
</template>

<script setup>
  const { proxy } = getCurrentInstance();
  const total = ref(567);
  const currentPage = ref(1);
  const limit = ref(20);
  const pageSizes = ref([10, 20, 30, 40, 50]);
  const pagelayout = ref("total, sizes, prev, pager, next");
  const backgroundpage = ref(true);
  const autoScrollpage = ref(true);
  const hiddenpage = ref(false);
  const changePage = () => {
    console.log("当前页码", currentPage.value);
    console.log("每页条数", limit.value);
    // 执行分页逻辑
    // 例如:获取数据、更新状态等
  };
</script>

<style lang="scss" scoped></style>

表格组件

安装横向滚动条

  • 这里就是当表格高度过高的时候.底部有个滚动条方便滑动
js
npm i el-table-horizontal-scroll -S
  • main.js
js
// 表格固定底部的滚动条
import horizontalScroll from "el-table-horizontal-scroll";

app.use(horizontalScroll);

封装 table 表格组件

components/MyTable.vue

注意

  1. 使用的时候修改 getList,依据后台的包来修改字段
html
<template>
  <el-card class="my-table-card">
    <div v-if="title !== ''" slot="header" class="my-table-header">
      <span v-if="totalFlag" class="title">共计{{ total }}条</span>
      <span class="title">{{ title }}</span>
      <span class="btn-box">
        <slot name="btn"></slot>
      </span>
    </div>
    <el-table
      v-loading="tableLoading"
      :data="tableList"
      :highlight-current-row="true"
      tooltip-effect="dark"
      border
      style="width: 100%"
      @selection-change="selectionChange"
      @sort-change="sortChange"
      v-horizontal-scroll="'always'"
    >
      <el-table-column
        v-if="isSelection"
        type="selection"
        align="center"
        width="50"
      ></el-table-column>
      <slot></slot>
    </el-table>
    <el-pagination
      v-if="hasPagination"
      background
      class="my-table-pagination"
      :current-page="currPage"
      :page-sizes="pageSizes"
      :page-size="limit"
      layout="total, sizes, prev, pager, next, jumper"
      :total="total"
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
    >
    </el-pagination>
  </el-card>
</template>

<script setup>
  import { ElMessage } from "element-plus";

  const route = useRoute();
  const emit = defineEmits(["data"]);
  const props = defineProps({
    title: {
      type: String,
      default: "",
    },
    api: {
      type: Function,
      required: true,
    },
    search: {
      type: Object,
      default: () => {
        return {};
      },
    },
    isSelection: {
      type: Boolean,
      default: false,
    },
    pageRecordName: {
      type: String,
      default: "",
    },
    totalFlag: {
      type: Boolean,
      default: false,
    },
    hasPagination: {
      type: Boolean,
      default: true,
    },
    fixedTableHeader: {
      type: Boolean,
      default: true,
    },
    pageSizes: {
      type: Array,
      default: () => {
        return [10, 20, 50, 100];
      },
    },
  });

  const scroll = ref(0);
  const mySearch = ref(props.search);
  const multipleSelection = ref([]);
  const tableList = ref([]);
  const tableLoading = ref(false);
  const total = ref(0);
  const currPage = ref(1);
  const totalPage = ref(1);
  const limit = ref(20);
  const myPageRecordName = ref(
    props.pageRecordName ? props.pageRecordName : route.fullPath
  );
  const order_field = ref("");
  const order_sort = ref("");
  const handleScroll = () => {
    scroll.value =
      document.documentElement.scrollTop || document.body.scrollTop; // 滚动条距顶部距离
    const containerEleTable = document.querySelector(`.el-table`); // el-table元素
    const containerEleHeader = document.querySelector(
      `.el-table .el-table__header-wrapper`
    ); // el-table元素的子元素el-table__header
    const containerEleHeaderLeftFixed = document.querySelector(
      `.el-table .el-table__fixed .el-table__fixed-header-wrapper`
    ); // el-table有左边fixed的table元素的子元素el-table__header
    const containerEleHeaderRightFixed = document.querySelector(
      `.el-table .el-table__fixed-right .el-table__fixed-header-wrapper`
    ); // el-table有右边fixed的table元素的子元素el-table__header

    const containerEleBody = document.querySelector(
      `.el-table .el-table__body-wrapper`
    ); // el-table元素的子元素el-table__body

    const containerEleHeaderTh = document.querySelectorAll(
      `.el-table thead tr th `
    );

    const offsetTop = containerEleTable.offsetTop - 50; // 头部固定条高度
    const table_w = window.getComputedStyle(containerEleTable).width;
    const height = window.getComputedStyle(containerEleHeader).height; // el-table元素的子元素el-table__header高度

    if (scroll.value > offsetTop) {
      // el-table元素的子元素el-table__header距顶部50个单位时
      containerEleHeader.classList.add("table-header-fixed"); // el-table元素的子元素el-table__header添加样式class类名 table-header-fixed

      containerEleBody.style.marginTop = height; // el-table元素的子元素el-table__body添加距marginTop,否则会有抖动

      containerEleHeader.style.width = table_w; // 控制el-table__header-wrapper宽度,解决el-table__header-wrapper超出table

      if (containerEleHeaderLeftFixed) {
        containerEleHeaderLeftFixed.classList.add("table-header-fixed");

        containerEleHeaderLeftFixed.style.width = table_w;
      }
      if (containerEleHeaderRightFixed) {
        containerEleHeaderRightFixed.classList.add("table-header-right-fixed");
      }
    } else {
      containerEleHeader.classList.remove("table-header-fixed");
      if (containerEleHeaderLeftFixed) {
        containerEleHeaderLeftFixed.classList.remove("table-header-fixed");
      }
      if (containerEleHeaderRightFixed) {
        containerEleHeaderRightFixed.classList.remove(
          "table-header-right-fixed"
        );
      }

      containerEleBody.style.marginTop = 0;
    }
    containerEleHeaderTh.forEach((ele) => {
      // 找到el-table__header-wrapper下边的th有is-hidden类名的删除is-hidden类名
      if (ele.classList.contains("is-hidden")) {
        ele.classList.add("is-hidden-z");
      }
    });
  };
  // 初始化
  const init = (reset = true) => {
    if (reset) {
      currPage.value = 1;
    }
    getList();
  };
  // 获取数据
  const getList = () => {
    tableLoading.value = true;
    const data = mySearch.value;
    data.page = currPage.value;
    data.size = limit.value;
    if (order_field.value != "") {
      data.order_field = order_field.value;
    }
    if (order_sort.value != "") {
      data.order_sort = order_sort.value;
    }

    props
      .api(data)
      .then((res) => {
        console.log(res);
        if (res.code === 200) {
          if (props.hasPagination) {
            // 有分页
            if (typeof res.total !== "undefined") {
              totalPage.value = Math.ceil(res.total / limit.value);
              total.value = res.total;
              tableList.value = [];
              tableList.value = tableList.value.concat(res.list);
            } else {
              if (typeof res.total !== "undefined") {
                totalPage.value = Math.ceil(res.total / limit.value);
                total.value = res.total;
                tableList.value = [];
                let result = res.list || res.data.data;
                tableList.value = tableList.value.concat(result);
              } else {
                currPage.value = res.curentpage;
                totalPage.value = res.page;
                total.value = res.total;
                tableList.value = res.list;
              }
            }
          } else {
            if (res.list) {
              tableList.value = res.list;
            } else {
              tableList.value = res.data;
            }
          }
          emit("data", res.data);
        } else {
          ElMessage.warning(res.msg);
        }
        tableLoading.value = false;
      })
      .catch(() => {
        // ElMessage.warning('请求失败了');
        // tableLoading.value = false;
      });
  };

  const savePage = () => {
    if (!myPageRecordName.value) {
      return false;
    }
    window.sessionStorage.setItem(
      myPageRecordName.value,
      JSON.stringify({ page: currPage.value, size: limit.value })
    );
  };

  const getPageRecord = () => {
    let data = window.sessionStorage.getItem(myPageRecordName.value);
    if (!data || typeof data === "undefined" || data === "null") {
      return false;
    }
    data = JSON.parse(data);
    currPage.value = data.page;
    limit.value = data.size;
  };

  const handleCurrentChange = (page) => {
    currPage.value = page;
    getList();
    savePage();
  };

  const handleSizeChange = (size) => {
    currPage.value = 1;
    limit.value = size;
    getList();
    savePage();
  };

  const selectionChange = (val) => {
    multipleSelection.value = val;
  };
  const getSelection = () => {
    return multipleSelection.value;
  };

  const getTableDate = () => {
    const tableDate = Object.assign({
      tableList: tableList.value,
      limit: limit.value,
      currPage: currPage.value,
    });
    return tableDate;
  };

  const sortChange = (column) => {
    order_field.value = column.prop;
    order_sort.value = column.order.replace("ending", "");
    getList();
  };

  watch(
    () => {
      return props.search;
    },
    (val) => {
      mySearch.value = val;
    }
  );

  onMounted(() => {
    // 设置分页
    getPageRecord();
    init(false); // 初始化
    if (props.fixedTableHeader) {
      window.addEventListener("scroll", handleScroll);
    }
  });
  onUnmounted(() => {
    window.removeEventListener("scroll", handleScroll);
  });
  defineExpose({
    init,
    getSelection,
    getTableDate,
  });
</script>

<style lang="scss" scoped>
  .my-table-card {
    :deep(.el-card__header) {
      padding: 10px 20px;
    }
    .my-table-header {
      display: flex;
      justify-content: space-between;
      .title {
        font-size: 12px;
        font-weight: bold;
        line-height: 32px;
      }
    }
    :deep(.el-table__header thead tr th) {
      background: #f9f9f9;
    }

    :deep(.el-table--small .el-table__body td) {
      padding: 5px 0;
    }
    .my-table-pagination {
      margin-top: 10px;
    }
  }
  .my-table-card {
    :deep(.el-table) {
      .table-header-fixed {
        position: fixed;
        top: 50px;
        left: auto;
        z-index: 100;
        border-top: 1px solid #dfe6ec;
      }
      .table-header-right-fixed {
        position: fixed;
        top: 50px;
        right: 46px;
        z-index: 200;
        border-top: 1px solid #dfe6ec;
      }
      .el-table__header {
        thead {
          tr {
            background: rgba(0, 0, 0, 0);
          }
        }
      }
    }
  }
  :deep(.is-hidden-z) {
    opacity: 0;
    // top: -50px;
  }
  :deep(.el-scrollbar__bar) {
    &.is-horizontal {
      height: 16px !important;
      background: #dfe6ec !important;
    }
  }
</style>

使用

vue
<template>
  <div class="useManagePage">
    <LineTitle :title="$t('message.route.userManage')">
      <el-button
        type="primary"
        @click="getselectdata"
        style="padding-left: 20px; padding-right: 20px"
        >获取选中数据</el-button
      >
    </LineTitle>
    <MyTable
      :api="getUserManageList"
      :search="searchdata"
      ref="userManageRef"
      isSelection="true"
    >
      <el-table-column prop="id" label="id" width="180" align="center" />

      <el-table-column
        prop="username"
        label="昵称"
        width="180"
        align="center"
      />

      <el-table-column prop="avatar" label="头像" width="180" align="center">
        <template #default="{ row }">
          <img
            :src="row.avatar"
            alt=""
            style="width: 50px; height: 50px; border-radius: 50%"
          />
        </template>
      </el-table-column>

      <el-table-column prop="openTime" label="创建时间" align="center">
        <template #default="{ row }">
          {{ getTime(row.openTime) }}
        </template>
      </el-table-column>
      <el-table-column prop="mobile" label="手机号" align="center" />

      <el-table-column prop="role" label="权限" align="center">
        <template #default="{ row }">
          <span v-for="(content, index) in row.role" :key="index">
            {{ content.title }}
          </span>
        </template>
      </el-table-column>
    </MyTable>
  </div>
</template>

<script setup>
import { getUserManageList } from "@/api/admin/userManager";
import { ElMessage } from "element-plus";
const searchdata = ref({});
const getTime = (timestamp) => {
  const date = new Date(parseInt(timestamp)); // 创建 Date 对象

  const year = date.getFullYear(); // 获取年份
  const month = date.getMonth() + 1; // 获取月份(注意月份从 0 开始,需要加 1)
  const day = date.getDate(); // 获取日期

  // 格式化为 YYYY-MM-DD
  const formattedDate = `${year}-${month.toString().padStart(2, "0")}-${day
    .toString()
    .padStart(2, "0")}`;
  return formattedDate;
};
const userManageRef = ref(null);

const getselectdata = () => {
  console.log(userManageRef.value.getSelection());
  let result = [];
  userManageRef.value.getSelection().forEach((item) => {
    result.push(item.id);
  });
  let str = result.join(",");
  ElMessage({
    message: `选中了id是${str}数据`,
    type: "success",
  });
};
</script>

<style lang="scss" scoped>
.useManagePage {
  padding-top: 30px;
  padding-left: 15px;
  padding-right: 15px;
}
</style>