vue3 ts element-plus vite--表格封装

主要做学习记录--原文

https://blog.csdn.net/weixin_45291937/article/details/125523244

学习成果--简单element-plus--表格封装:

1.因为element会废弃Pagination 事件---v-model和"事件"均有案例

效果图:

1.创建Table.vue

   src/components/Table/index.vue

<template>
  <div class="home">
    <el-table
      :border="true"
      style="width: 100%"
      height="100%"
      :data="tableData"
      :header-cell-style="{ backgroundColor: '#f5f5f5' }"
      :cell-style="{ padding: '5px' }"
    >
      <template #empty>
        <el-empty description="暂无数据"></el-empty>
      </template>
      <template v-for="column in columns" :key="column.prop || column.key">
        <el-table-column
          label="序号"
          width="100"
          :align="column.align"
          v-if="column.label == '序号'"
        >
          <template #default="scope">
            <slot name="xiuhao" :scope="scope">
              <span
                >{{
                  scope.$index +
                  (pagination.currentPage - 1) * pagination.pageSize +
                  1
                }}
              </span>
            </slot>
          </template>
        </el-table-column>
        <el-table-column
          v-else-if="column.slot"
          :label="column.label"
          :width="column.width"
          header-:align="column.align"
          :align="column.align"
        >
          <template #default="scope">
            <slot :name="column.slot" :scope="scope"></slot>
          </template>
        </el-table-column>
        <el-table-column
          v-else
          :label="column.label"
          :width="column.width"
          :prop="column.prop"
          show-overflow-tooltip
          :align="column.align"
        >
          <template #default="{ row, $index }">
            <!-- 对时间处理 -->
            <template v-if="column.type === 'date'">
              <span>{{
                timeFormat(
                  row[column.prop as string],
                  column.dateFormat as string
                )
              }}</span>
            </template>
          </template></el-table-column
        >
      </template>
    </el-table>
    <!-- <div class="pagination">
      <el-pagination
        style="margin-top: 12px"
        :current-page="pagination.currentPage"
        :page-sizes="pagination.pageSizes"
        :page-size="pagination.pageSize"
        layout="total, sizes, prev, pager, next, jumper"
        :total="pagination.total"
        @size-change="pageSizeChange"
        @current-change="currentPageChange"
        prev-text="上一页"
        next-text="下一页"
        hide-on-single-page
      >
      </el-pagination>
    </div> -->
    <div class="pagination">
      <el-pagination
        style="margin-top: 12px"
        v-model:current-page="pagination.currentPage"
        v-model:page-sizes="pagination.pageSizes"
        v-model:page-size="pagination.pageSize"
        layout="total, sizes, prev, pager, next, jumper"
        v-model:total="pagination.total"
        hide-on-single-page
      >
      </el-pagination>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { toRefs, reactive, watch } from "vue";
import { timeFormat } from "@/utils/common";
interface TableProps {
  tableData: Array<object>; // table的数据
  columns: Table.Column[]; // 每列的配置项
  pagination: Table.Pagination; //页码
}
const props = defineProps<TableProps>();
interface EmitEvent {
  (e: "selection-change", params: any): void; // 当选择项发生变化时会触发该事件
  (e: "size-change", pageSize: number): void; // pageSize事件
  (e: "current-change", currentPage: number): void; // currentPage按钮组事件
  (e: "pagination-change", pagination: object): void; //pageSize事件和currentPage按钮组事件
}
// 使用 v-model 放弃elemntui-Pagination方法
// 监听 current-page ,  page-size 的改变,
const emit = defineEmits<EmitEvent>();
const { pagination } = toRefs(props);
watch(
  () => pagination.value.currentPage,
  (newValue, oldValue) => {
    pagination.value.currentPage = newValue;
    emit("pagination-change", pagination);
  }
);
watch(
  () => pagination.value.pageSize,
  (newValue, oldValue) => {
    pagination.value.pageSize = newValue;
    pagination.value.currentPage = 1;
    emit("pagination-change", pagination);
  }
);
/* 
  * 注册分页 change 方法
*/
// const emit = defineEmits<EmitEvent>();
// const { pagination } = toRefs(props);
// // 切换pageSize
// const pageSizeChange = (pageSize: number) => {
//   pagination.value.pageSize = pageSize;
//   pagination.value.currentPage = 1;
//   emit("pagination-change", pagination);
// };
// // 切换currentPage
// const currentPageChange = (currentPage: number) => {
//   pagination.value.currentPage = currentPage;
//   emit("pagination-change", pagination);
// };
</script>

<style lang="scss" scoped>
.home {
  width: 100%;
  height: 100%;
}

.pagination {
  width: 100%;
  display: flex;
  margin-top: 10px;
  justify-content: flex-end;
}

.el-tooltip__popper {
  max-width: 20% !important;
}

.el-tooltip__popper,
.el-tooltip__popper.is-dark {
  background: rgb(48, 65, 86) !important;
  color: #fff !important;
  line-height: 20px;
}
</style>

2.创建 index.d.ts 声明为全局的类型

   src/components/Table/index.d.ts

// table表格
 declare namespace Table {
  type VNodeChild = import("vue").VNodeChild;
  type Type = "selection" | "index" | "expand" | "image" | "date";
  type Size = "large" | "default" | "small";
  type Align = "center" | "left" | "right";
  type Command = string | number;
  type DateFormat =
    | "yyyy-MM-dd"
    | "yyyy-MM-dd hh:mm:ss"
    | "yyyy-MM-DD hh:mm"
    | "yyyy-MM";
  type Order = "ascending" | "descending";
  interface ButtonItem {
    name: string;
    command: Command;
    size?: Size;
    type?: "primary" | "success" | "warning" | "danger" | "info";
  }
  interface 
  interface Sort {
    prop: string;
    order: Order;
    init?: any;
    silent?: any;
  }
  interface Column {
    // 对应列的类型。 如果设置了selection则显示多选框; 如果设置了 index 则显示该行的索引(从 1 开始计算); 如果设置了 expand 则显示为一个可展开的按钮
    type?: Type;
    label?: string;
    prop?: string;
    slot?: string;
    width?: string;
    align?: Align;
    dateFormat?: DateFormat; // 显示在页面中的日期格式,简单列举了几种格式, 可自行配置
    showOverflowTooltip?: boolean;
    buttons?: ButtonItem[];
    render?: (row?: Record<string, any>, index?: number) => VNodeChild; // 渲染函数,渲染这一列的每一行的单元格
    sortable?: boolean | "custom"; // 对应列是否可以排序, 如果设置为 'custom',则代表用户希望远程排序,需要监听 Table 的 sort-change 事件
    headerRender?: ({ column, index }) => VNodeChild; // 渲染函数,渲染列表头
    headerSlot?: string; // 自定义表头插槽名字
    children?: Column[]; // 配置多级表头的数据集合, 具体用法可参考多级表头使用示例。
  }
  interface Options {
    height?: string | number;
    // Table 的高度, 默认为自动高度。 如果 height 为 number 类型,单位 px;如果 height 为 string 类型,则这个高度会设置为 Table 的 style.height 的值,Table 的高度会受控于外部样式。
    stripe?: boolean; // 是否为斑马纹 table
    maxHeight?: string | number; // Table 的最大高度。 合法的值为数字或者单位为 px 的高度。
    size?: Size; // Table 的尺寸
    showHeader?: boolean; // 是否显示表头,
    tooltipEffect?: "dark" | "light"; // tooltip effect 属性
    showPagination?: boolean; // 是否展示分页器
    paginationConfig?: Pagination; // 分页器配置项,详情见下方 paginationConfig 属性,
    rowStyle?: ({ row, rowIndex }) => stirng | object; // 行的 style 的回调方法,也可以使用一个固定的 Object 为所有行设置一样的 Style。
    headerCellStyle?: import("vue").CSSProperties; // 表头单元格的style样式,是一个object为所有表头单元格设置一样的 Style。注:CSSProperties类型就是一个对象,像正常在style中写css一样 {color: #f00}
    defaultSort?: Sort; // 默认的排序列的 prop 和顺序。 它的 prop 属性指定默认的排序的列,order 指定默认排序的顺序。
    rowKey?: string; // 行数据的 Key,用来优化 Table 的渲染。
  }
  interface Pagination {
    total?: number; // 总条目数
    currentPage: number; // 当前页数,支持 v-model 双向绑定
    pageSize: number; // 每页显示条目个数,支持 v-model 双向绑定
    pageSizes?: number[]; // 每页显示个数选择器的选项设置
    layout?: string; // 组件布局,子组件名用逗号分隔
    background?: boolean; // 是否为分页按钮添加背景色
  }
}

3.创建 common.ts

   src/utils/common.ts

**
 * 时间戳转时间
 * @param {Number} date 时间戳
 * @param {String} format 需要的格式
 * @return {String} 返回格式化完成时间
 */
interface timeFormat {
  (date: Date | any, format: string): String;
}
export const timeFormat: timeFormat = (date, format) => {
  date = new Date(date);
  if (date == "Invalid Date") {
    return "";
  }
  let map: any = {
    M: date.getMonth() + 1, //月份
    d: date.getDate(), //日
    h: date.getHours(), //小时
    m: date.getMinutes(), //分
    s: date.getSeconds(), //秒
    q: Math.floor((date.getMonth() + 3) / 3), //季度
    S: date.getMilliseconds(), //毫秒
  };
  format = format.replace(/([yMdhmsqS])+/g, function (all: any, t: any) {
    var v = map[t];
    if (v !== undefined) {
      if (all.length > 1) {
        v = "0" + v;
        v = v.substr(v.length - 2);
      }
      return v;
    } else if (t === "y") {
      return (date.getFullYear() + "").substr(4 - all.length);
    }
    return all;
  });
  return format;
};

4.引用

<template>
  <div>
    <!-- <div style="height: 400px">
      <Table
        :columns="tableColumn"
        :table-data="tableData"
        :pagination="pagination"
        @pagination-change="paginationChange"
      >
        <template v-slot:xb="{ scope }">
          <span> {{ scope.row.gender }}</span>
        </template>
      </Table>
    </div> -->
    <div style="height: 400px">
      <Table
        :columns="tableColumn"
        :table-data="tableData"
        v-model:pagination="pagination"
        @pagination-change="paginationChange"
      >
        <template v-slot:xb="{ scope }">
          <span> {{ scope.row.gender }}</span>
        </template>
      </Table>
    </div>
  </div>
</template>

<script setup lang="ts">
import Table from "@/components/Table/index.vue";
import { reactive } from "vue";
interface User {
  date: number;
  name: string;
  address: string;
  gender: number;
}
const tableData = reactive<User[]>([
  {
    date: 1660737564000,
    name: "佘太君",
    address: "上海市普陀区金沙江路 1516 弄",
    gender: 0,
  },
  {
    date: 1462291200000,
    name: "王小虎",
    address: "上海市普陀区金沙江路 1517 弄",
    gender: 0,
  },
  {
    date: 1462032000000,
    name: "王小帅",
    address: "上海市普陀区金沙江路 1519 弄",
    gender: 1,
  },
  {
    date: 1462204800000,
    name: "王小呆",
    address: "上海市普陀区金沙江路 1516 弄",
    gender: 1,
  },
  {
    date: 1462204800000,
    name: "王小呆",
    address: "上海市普陀区金沙江路 1516 弄",
    gender: 1,
  },
  {
    date: 1462204800000,
    name: "王小呆",
    address: "上海市普陀区金沙江路 1516 弄",
    gender: 1,
  },
  {
    date: 1462204800000,
    name: "王小呆",
    address: "上海市普陀区金沙江路 1516 弄",
    gender: 1,
  },
  {
    date: 1462204800000,
    name: "王小呆",
    address: "上海市普陀区金沙江路 1516 弄",
    gender: 1,
  },
  {
    date: 1462204800000,
    name: "王小呆",
    address: "上海市普陀区金沙江路 1516 弄",
    gender: 1,
  },
  {
    date: 1462204800000,
    name: "王小呆",
    address: "上海市普陀区金沙江路 1516 弄",
    gender: 1,
  },
]);
const tableColumn = reactive<Table.Column[]>([
  { label: "序号" },
  { prop: "name", width: "100", label: "名字", align: "center" },
  { prop: "gender", width: "100", label: "性别", slot: "xb", align: "center" },
  {
    prop: "address",
    label: "地址",
    headerSlot: "addressHeader",
    showOverflowTooltip: true,
    align: "center",
  },
  {
    type: "date",
    prop: "date",
    label: "时间",
    align: "center",
    width: "150",
    dateFormat: "yyyy-MM-dd",
  },
]);
const pagination = reactive<Table.Pagination>({
  total: 20,
  currentPage: 1,
  pageSize: 10,
  pageSizes: [5, 10, 15, 20],
});
// table 传递的数据
const paginationChange = (res: any) => {
  console.log(res.value,pagination.currentPage);
};
</script>

<style scoped></style>

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值