Giải pháp xử lý các vấn đề thường gặp với Vxe-Grid

1. Sử dụng template trong Slot

Khi cần render nội dung tùy chỉnh trong ô bảng, cách viết JSX thông thường có thể không hoạt động như mong đợi. Thay vì sử dụng trực tiếp JSX, hãy sử dụng hàm h để tạo element với domProps:

{
  title: '',
  headerClassName: 'custom-header-style',
  field: 'customField',
  showOverflow: false,
  slots: {
    default: (params, h) => [
      h('span', {
        props: {
          type: 'text'
        },
        domProps: {
          innerHTML: formatCellContent(params)
        }
      })
    ]
  }
}

2. Gộp ô tiêu đề bảng (Merge Header)

Để gộp các ô trong tiêu đề bảng, có thể kết hợp giữa CSS và JavaScript để điều khiển thuộc tính rowspan:

// JavaScript xử lý gộp ô
const targetCell = document.querySelector('.merged-cell');
if (targetCell) {
  targetCell.setAttribute('rowspan', '3');
}

const cellsToHide = document.querySelectorAll('.hidden-cell');
cellsToHide.forEach(cell => {
  cell.style.display = 'none';
});

Cấu hình cột tương ứng:

{
  fixed: 'left',
  title: 'Tiêu đề đã gộp',
  width: '120',
  headerClassName: 'merged-cell',
  children: [{
    title: '',
    headerClassName: 'hidden-cell',
  }]
}

Lưu ý quan trọng khi gộp ô:

  • Vấn đề về vị trí: Nếu sử dụng thuộc tính fixed cho cột được gộp, có thể gây ra hiện tượng nhảy vị trí. Nên loại bỏ fixed hoặc tắt tính năng highlight cột bằng cách set isCurrent: false trong columnConfig.
  • Phản ứng với thay đổi kích thước: Khi cửa sổ trình duyệt thay đổi kích thước, phương thức DOM manipulation có thể mất hiệu lực. Giải pháp tốt hơn là sử dụng CSS thuần:
.vxe-header--column {
  line-height: initial;
  padding: 0 !important;
  
  &.merged-cell {
    background-size: 0px 100%, 100% 0px;
  }
}

3. Tùy chỉnh chiều cao dòng Footer

Tùy thuộc vào giá trị size của vxe-table, cần áp dụng CSS phù hợp:

/* Mặc định (không set size) */
.vxe-table--render-default.border--full .vxe-footer--column {
  height: 28px;
}

/* size="medium" */
.vxe-table--render-default.size--medium .vxe-footer--column.col--ellipsis {
  height: 28px;
}

/* size="small" */
.vxe-table--render-default.size--small .vxe-footer--column.col--ellipsis {
  height: 28px;
}

/* size="mini" */
.vxe-table--render-default.size--mini .vxe-footer--column.col--ellipsis {
  height: 28px;
}

4. Căn chỉnh nội dung ô theo điều kiện

Để căn giữa một số dòng đầu tiên trong khi các dòng còn lại căn trái:

// Trong cấu hình bảng
className: (params) => customRowClass(params),

// Hàm xử lý class
customRowClass(params) {
  const { rowIndex } = params;
  if (rowIndex < 9) {
    return 'center-aligned-cell';
  }
  return '';
}

CSS tương ứng:

.vxe-body--column {
  line-height: initial;
  
  &.center-aligned-cell {
    text-align: center;
  }
  
  &.dashed-border-top {
    border-top: dashed #d9001b;
  }
}

5. Bật chế độ chỉnh sửa cho ô cụ thể

Khi muốn chỉ một số ô trong dòng có thể chỉnh sửa, sử dụng thuộc tính edit-render kết hợp với điều kiện trong editMethod:

{
  field: 'editableField',
  title: 'Cột có thể sửa',
  editRender: {
    name: 'input',
    enabled: (params) => {
      const { row, column } = params;
      // Chỉ cho phép chỉnh sửa khi thỏa mãn điều kiện
      return row.canEdit === true;
    }
  }
}

6. Thêm menu chuột phải cho Footer

Sử dụng sự kiện cell-context-menu và kiểm tra vùngFooter thông qua type trong params:

onCellContextMenu(params) {
  const { type, column } = params;
  if (type === 'footer') {
    // Hiển thị context menu tùy chỉnh cho footer
    showCustomContextMenu(params);
  }
}

7. Xử lý khoảng trắng sau khi gộp ô với Flex Grid

Sau khi thực hiện gộp ô, có thể xuất hiện khoảng trắng ở bên phải dẫn đến thanh cuộn ngang không cần thiết. Cần kiểm tra và điều chỉnh lại width của các cột hoặc sử dụng CSS để ẩn khoảng trắng:

.vxe-table--body {
  width: 100% !important;
}

.vxe-table--body-wrapper {
  overflow-x: hidden;
}

8. Sự cố gộp Footer không hoạt động

Khi gộp footer đột ngột không còn hiệu lực, kiểm tra các nguyên nhân sau:

  • Dữ liệu footer chưa được cập nhật đúng format
  • Thứ tự gọi hàm setFooterCellMerge không đúng thời điểm
  • Cần gọi lại hàm gộp ô sau khi dữ liệu thay đổi

9. Thêm sự kiện tùy chỉnh trong Edit Render với JSX

Khi sử dụng vxe-input với type là number, các phím mũi tên lên/xuống có thể gây ra hành vi không mong muốn. Cần xử lý trong sự kiện input:

{
  field: 'numberField',
  editRender: {
    name: '$input',
    props: { type: 'number' },
    events: {
      input: (params, value) => {
        const { row } = params;
        // Xử lý giá trị mới
        row.numberField = Number(value);
      },
      keydown: (params, event) => {
        // Ngăn chặn hành vi mặc định của phím mũi tên
        if (event.key === 'ArrowUp' || event.key === 'ArrowDown') {
          event.stopPropagation();
        }
      }
    }
  }
}

10. Dữ liệu cập nhật nhưng giao diện không thay đổi

Khi gán dữ liệu qua vòng lặp, Vue có thể không phát hiện thay đổi. Sử dụng this.$set hoặc gán lại toàn bộ mảng:

// Thay vì
this.tableData.forEach((item, index) => {
  item.field = newValue;
});

// Nên sử dụng
const updatedData = [...this.tableData];
updatedData.forEach((item) => {
  item.field = newValue;
});
this.tableData = updatedData;

// Hoặc sử dụng $set
this.$set(this.tableData, index, { ...this.tableData[index], field: newValue });

11. Hiệu ứng giật khi render lại bảng đã gộp

Khi bảng được render lại và có cell merge, hiệu ứng giật có thể xảy ra. Giải pháp là thực hiện merge lại sau khi render hoàn tất:

this.$nextTick(() => {
  this.applyCellMerge();
});

12. Tùy chỉnh điều kiện double-click để chỉnh sửa

Để kiểm soát việc bật chế độ edit khi double-click:

{
  field: 'conditionalEdit',
  editRender: {
    name: 'input',
    enabled: false // Tắt edit mặc định
  }
}

// Xử lý sự kiện cell-dblclick
onCellDblclick(params) {
  const { row, column } = params;
  if (this.isEditableCell(row, column)) {
    this.$refs.gridRef.setActiveCell(row, column);
  }
}

13. Gộp lại ô sau khi edit và render lại bảng

Sau khi chỉnh sửa dữ liệu, các ô đã gộp sẽ mất hiệu lực. Cần gọi lại hàm gộp ô:

async handleDataUpdate() {
  await this.reloadData();
  this.$nextTick(() => {
    this.restoreMergedCells();
  });
}

14. Dòng gộp bị tăng chiều cao khi bật chế độ edit

Vấn đề này xảy ra do editor thay đổi layout của ô. Điều chỉnh CSS cho cell đang edit:

.vxe-body--column.col--edit {
  height: auto !important;
  
  .vxe-input--inner {
    height: 100%;
  }
}

15. Tích hợp Tippy.js với dữ liệu đã thay đổi

Khi sử dụng tooltip library như Tippy.js, có thể xuất hiện nhiều tooltip cho cùng một ô. Cần hủy tooltip cũ trước khi tạo mới:

let existingTooltip = null;

function updateTooltip(element, content) {
  if (existingTooltip) {
    existingTooltip.destroy();
  }
  existingTooltip = tippy(element, {
    content: content,
    onHidden(instance) {
      instance.destroy();
    }
  });
}

16. Xử lý Enter trong chế độ edit và blur event

Khi nhấn Enter để đóng editor, cần ngăn chặn việc trigger blur event không mong muốn:

{
  editRender: {
    name: 'input',
    events: {
      keydown: (params, event) => {
        if (event.key === 'Enter') {
          event.preventDefault();
          // Xử lý logic đóng editor
          params.$table.clearEdit();
          // Gọi callback nếu cần
          this.onEditComplete(params);
        }
      }
    }
  }
}

Thẻ: vxe-table vxe-grid vue-table data-grid frontend

Đăng vào ngày 19 tháng 9 lúc 01:29