VxeTable表格,简单的二次封装

6,287 阅读1分钟
<script>
/**
 * 简介:VxeTable 简单表格的二次封装
 * 事件:tableChange(分页发生改变时会触发该事件),sortChangeEvent(排序时会触发的函数),
 * radioChange(单选框选择) cellDblclick(表格单元格双击事件) cellClick(点击一行)checkbox(多选框触发)
 */
export default {
  name: "VXETable2",
  props: {
    toggleMethod: {
      // 	该方法在展开或关闭触发之前调用,可以通过返回值来决定是否允许继续执行
      type: Function,
    },
    columns: {
      // 表头数据
      type: Array,
      default: () => [],
    },
    autoResize: {
      // 自动监听父元素的变化去重新计算表格
      type: Boolean,
      default: true,
    },
    border: {
      // 是否添加边框
      type: Boolean,
      default: true,
    },
    rowKey: {
      // 是否需要为每一行的 VNode 设置 key 属性(非特殊情况下没必要设置)
      type: Boolean,
      default: true,
    },
    resizable: {
      //	所有的列是否允许拖动列宽调整大小
      type: Boolean,
      default: true,
    },
    showOverflow: {
      //	设置所有内容过长时显示为省略号(如果是固定列建议设置该值,提升渲染速度)
      type: Boolean,
      default: true,
    },
    highlightHoverRow: {
      //		鼠标移到行是否要高亮显示
      type: Boolean,
      default: true,
    },
    height: {
      // 表格的高度;支持铺满父容器或者固定高度,如果设置 auto 为铺满父容器(如果设置为 auto,则必须确保存在父节点且不允许存在相邻元素)
      type: [String, Number],
      default: "auto",
    },
    maxHeight: {
      // 表格的最大高度
      type: String, //%, px
      default: "",
    },
    align: {
      //所有的列对齐方式 left(左对齐), center(居中对齐), right(右对齐)
      type: String,
      default: "center",
    },
    rowHeight: {
      //行高
      type: String,
      default: "",
    },
    rowStyle: {
      // 行样式
      type: [String, Object, Function],
    },
    containerHeight: {
      //父盒子的高度
      type: String,
      default: "100%",
    },
    containerMaxHeight: { type: String, default: "" }, //父盒子的最大高度
    containerMinHeight: { type: String, default: "" }, //父盒子的最小高度
    pager: {
      // 开启分页
      type: Boolean,
      default: false,
    },
    currentPage: {
      //当前页
      type: Number,
      default: 1,
    },
    pageSize: {
      //每页大小
      type: Number,
      default: 5,
    },
    pageSizes: {
      //	每页大小选项列表
      type: Array,
      default: () => [50, 100, 150],
    },
    total: {
      //总条数
      type: Number,
      default: 0,
    },
    sortMethod: {
      // 是否开启自定义排序
      type: Boolean,
      default: false,
    },
    checkField: {
      // 每行的选择字段
      type: String,
      default: "pitch",
    },
    autoHidden: {
      // 	当只有一页时自动隐藏
      type: Boolean,
      default: false,
    },
    //是否显示全选按钮(如果 checkStrictly=true 则默认为 false)
    showHeader: {
      type: Boolean,
      default: true,
    },
    checkMethod: Function, //	是否允许勾选的方法,该方法的返回值用来决定这一行的 checkbox 是否可以勾选
  },
  render(h) {
    // tooltip-config={{ showAll: true }}
    return (
      // containerMaxHeight
      // containerMinHeight
      <div>
        <div
          style={{
            height: this.containerHeight,
            width: "100%",
            maxHeight: this.containerMaxHeight,
            minHeight: this.containerMinHeight,
          }}
        >
          <vxe-table
            scroll-y={{ enabled: true, gt: 0 }}
            row-style={this.rowStyle}
            ref="xTable"
            row-config={{ height: this.rowHeight }}
            border={this.border}
            auto-resize={this.autoResize}
            row-key={this.rowKey}
            resizable={this.resizable}
            show-overflow={this.showOverflow}
            highlight-hover-row={this.highlightHoverRow}
            align={this.align}
            height={this.height}
            max-height={this.maxHeight}
            expand-config={{
              trigger: "cell",
              showIcon: false,
              accordion: true,
              toggleMethod: this.toggleMethod,
            }}
            resizable-config={{ minWidth: 10 }}
            radio-config={{ trigger: "row" }}
            checkbox-config={{
              checkField: this.checkField,
              trigger: "row",
              checkMethod: this.checkMethod,
              showHeader: this.showHeader,
            }}
            onSort-change={this.sortChangeEvent}
            sort-config={{
              remote: this.sortMethod,
              trigger: "cell",
              orders: ["asc", "desc", "default"],
            }}
            clear-sort={this.clearSort}
            onCell-click={this.cellClick}
            onCell-dblclick={this.onCellDblclick}
            onCheckbox-change={this.checkbox}
            onCheckbox-all={this.checkbox}
            onRadio-change={this.radioChange}
          >
            {this.columns.map((item, index) => {
              return item.type === "checkbox" ||
                item.type === "radio" ||
                item.type === "seq"
                ? this.vxeTableChechboxRadio(item, index)
                : item.type === "expand"
                ? this.vxeTableExpand(item, index)
                : this.vxeTable(item, index);
            })}
          </vxe-table>
        </div>

        {this.pager ? (
          // 开启分页
          <vxe-pager
            perfect
            size="mini"
            current-page={this.currentPage}
            page-size={this.pageSize}
            page-sizes={this.pageSizes}
            total={this.total}
            auto-hidden={this.autoHidden}
            layouts={[
              "PrevPage",
              "JumpNumber",
              "NextPage",
              "FullJump",
              "Sizes",
              "Total",
            ]}
            onPage-change={(event) => this.pageChange(event)}
          />
        ) : (
          ""
        )}
      </div>
    );
  },
  methods: {
    // 隐藏列
    getColumnByField(field) {
      // this.$emit("cellClick", e);
      if(!field){
        return
      }
      // console.log("隐藏列",field)
      this.$refs.xTable.hideColumn(this.$refs.xTable.getColumnByField(field));
      // return
    },
    // 点击行
    cellClick(e) {
      this.$emit("cellClick", e);
    },
    // 表格单元格双击事件
    onCellDblclick(e) {
      this.$emit("cellDblclick", e);
    },
    // 获取当前表格的列(收集到的全量列、全量表头列、处理条件之后的全量表头列、当前渲染中的表头列
    getTableColumn() {
      return this.$refs.xTable.getTableColumn();
    },
    // 获取表格的可视的列
    getColumns() {
      return this.$refs.xTable.getColumns();
    },
    // 刷新列配置(对于动态修改属性、显示/隐藏列等场景下可能会用到)
    refreshColumn() {
      this.$refs.xTable.refreshColumn();
    },
    //  重新计算表格
    recalculate(is = true) {
      this.$refs.xTable.recalculate(is);
      this.refreshColumn();
    },
    // 加载数据并清除所有状态(对于表格数据需要重载、局部递增的场景中可能会用到)
    reloadData(data) {
      if (!Array.isArray(data)) data = [];
      this.$refs.xTable.reloadData(data);
    },
    //手动处理数据(对于手动更改了排序、筛选...等条件后需要重新处理数据时可能会用到)
    updateData(data) {
      if (!Array.isArray(data)) data = [];
      this.$refs.xTable.updateData(data);
    },
    // 加载数据(对于表格数据需要重载、局部递增场景下可能会用到)
    loadData(data) {
      if (!Array.isArray(data)) data = [];
      this.$refs.xTable.loadData(data);
    },
    // 分页发生改变时会触发该事件
    pageChange(e) {
      this.$emit("tableChange", e);
    },
    // 排序时会触发的函数 "desc"  降序 ,"asc" 升序,"default"默认排序
    sortChangeEvent(e) {
      this.$emit("sortChangeEvent", e);
    },
    // 分解字段
    itemField(row, field) {
      let field_zd = field?.split(".");
      if (Array.isArray(field_zd) && field_zd?.length > 1) {
        // 如果没有对象数据,界面上渲染空字符串
        if (!row[field_zd[0]]) {
          return "";
        }
        return row[field_zd[0]][field_zd[1]];
      }
      return row[field];
    },
    // 多选框触发
    checkbox(e) {
      this.$emit("checkbox", e);
    },
    // 单选框的选择
    radioChange(e) {
      this.$emit("radioChange", e);
    },
    // 渲染 vxe-column 的 type = checkbox | radio |xuhao
    vxeTableChechboxRadio(item, index) {
      return (
        <vxe-column
          key={index}
          type={item.type}
          sortable={item.sortable} //  是否开启排序
          title={item.title} //	列标题
          width={item.width} //列宽度 px, % number | string
          min-width={item.minWidth} //最小列宽度会自动将剩余空间按比例分配 number | string px, %
          fixed={item.fixed} // 将列固定在左侧或者右侧注意固定列应该放在左右两侧的位置left固定左侧), right固定右侧)
        />
      );
    },
    // 渲染张开行处理
    vxeTableExpand(item, index) {
      console.log(item);
      return (
        <vxe-column
          key={index}
          type={item.type}
          sortable={item.sortable} //  是否开启排序
          title={item.title} //	列标题
          width={item.width} //列宽度 px, % number | string
          min-width={item.minWidth} //最小列宽度会自动将剩余空间按比例分配 number | string px, %
          fixed={item.fixed} // 将列固定在左侧或者右侧注意固定列应该放在左右两侧的位置left固定左侧), right固定右侧scopedSlots={{
            // 显示插槽
            default: (posrt) => {
              let field = item.field ? this.filterField(item.field) : "";
              return h(
                "span",
                this.$scopedSlots[field] //先判断有没有具名插槽,有就渲染
                  ? this.$scopedSlots[field]({
                      row: posrt.row,
                      rowIndex: posrt.$rowIndex,
                    })
                  : this.$scopedSlots["default"] //判断有没有默认插槽,有就渲染默认插槽
                  ? this.$scopedSlots["default"]({
                      row: posrt.row,
                      rowIndex: posrt.$rowIndex,
                      field: item.field,
                      text: this.itemField(posrt.row, item.field),
                    })
                  : this.itemField(posrt.row, item.field) //渲染正常的数据
              );
            },
            content: (posrt) => {
              // row  一行的数据
              // rowIndex 索引
              return h(
                "div",
                this.$scopedSlots["content"] //判断有没有默认插槽,有就渲染默认插槽
                  ? this.$scopedSlots["content"]({
                      row: posrt.row,
                      rowIndex: posrt.$rowIndex,
                      field: item.field,
                      text: this.itemField(posrt.row, item.field),
                    })
                  : this.itemField(posrt.row, item.field) //渲染正常的数据
              );
            },
          }}
        />
      );
    },
    // 渲染普通的 vxe-column
    vxeTable(item, index) {
      // console.log(item);
      return (
        <vxe-column
          key={index}
          title={item.title} //	列标题
          field={item.field} //列字段名
          width={item.width} //列宽度 px, % number | string
          min-width={item.minWidth} //最小列宽度会自动将剩余空间按比例分配 number | string px, %
          fixed={item.fixed} // 将列固定在左侧或者右侧注意固定列应该放在左右两侧的位置left固定左侧), right固定右侧sortable={item.sortable} //  是否开启排序
          sort-type={item.sortType} //排序的字段类型比如字符串转数值等 	auto, number, string
          align={item.align ? item.align : this.align} //left左对齐), center居中对齐), right右对齐scopedSlots={{
            default: (posrt) => {
              // row  一行的数据
              // rowIndex 索引
              // console.log(this.$scopedSlots);
              // console.log(item.field);
              let field = item.field ? this.filterField(item.field) : "";
              let text = this.itemField(posrt.row, item.field);
              // console.log(this.$scopedSlots[field], field);
              return h(
                "span",
                this.$scopedSlots[field] //先判断有没有具名插槽,有就渲染
                  ? this.$scopedSlots[field]({
                      row: posrt.row,
                      rowIndex: posrt.$rowIndex,
                      field: item.field,
                      text,
                    })
                  : this.$scopedSlots["default"] //判断有没有默认插槽,有就渲染默认插槽
                  ? this.$scopedSlots["default"]({
                      row: posrt.row,
                      rowIndex: posrt.$rowIndex,
                      field: item.field,
                      text,
                    })
                  : text //渲染正常的数据
              );
            },
          }}
        />
      );
    },
    // 分割多字段
    filterField(field) {
      let field_zd = field?.split(".");
      return field_zd?.length === 1 ? field_zd[0] : field_zd[1];
    },
  },
};
</script>