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
fixedcho cột được gộp, có thể gây ra hiện tượng nhảy vị trí. Nên loại bỏfixedhoặc tắt tính năng highlight cột bằng cách setisCurrent: falsetrongcolumnConfig. - 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
setFooterCellMergekhô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);
}
}
}
}
}