Element Table组件的可拖动改变列宽度需要当table为带边框表格时并且resizable属性为true时可以拖动改变列宽度,具体实现在table-header组件中
鼠标在相对应的列移动时
handleMouseMove(event, column) {
if (column.children && column.children.length > 0) return;
let target = event.target;
// 找到事件对象th
while (target && target.tagName !== "TH") {
target = target.parentNode;
}
if (!column || !column.resizable) return;
// border为真且列没有在移动时
if (!this.dragging && this.border) {
// 获取事件对象的DOMRect对象
let rect = target.getBoundingClientRect();
const bodyStyle = document.body.style;
// 边界条件 满足这个条件时 添加上‘col-resize’样式
if (rect.width > 12 && rect.right - event.pageX < 8) {
bodyStyle.cursor = "col-resize";
if (hasClass(target, "is-sortable")) {
target.style.cursor = "col-resize";
}
// 将正在移动的列赋值给draggingColumn
this.draggingColumn = column;
} else if (!this.dragging) {
bodyStyle.cursor = "";
if (hasClass(target, "is-sortable")) {
target.style.cursor = "pointer";
}
this.draggingColumn = null;
}
}
},
这一段代码主要做的就是当鼠标移动到满足条件时,将光标样式改为可移动光标样式,再将当前列赋值给draggingColumn
鼠标按下时
handleMouseDown(event, column) {
if (column.children && column.children.length > 0) return;
if (this.draggingColumn && this.border) {
this.dragging = true;
// 控制table组件ref为resizeProxy的显示 当我们按下鼠标拖动时跟着走的那根线
this.$parent.resizeProxyVisible = true;
const table = this.$parent;
const tableEl = table.$el;
const tableLeft = tableEl.getBoundingClientRect().left;
const columnEl = this.$el.querySelector(`th.${column.id}`);
const columnRect = columnEl.getBoundingClientRect();
const minLeft = columnRect.left - tableLeft + 30;
addClass(columnEl, "noclick");
// 拖拽时的状态,用于后面的计算
this.dragState = {
startMouseLeft: event.clientX,
startLeft: columnRect.right - tableLeft,
startColumnLeft: columnRect.left - tableLeft,
tableLeft,
};
const resizeProxy = table.$refs.resizeProxy;
// resizeProxy是使用绝对定位 赋值给left
resizeProxy.style.left = this.dragState.startLeft + "px";
const handleMouseMove = (event) => {
const deltaLeft = event.clientX - this.dragState.startMouseLeft;
const proxyLeft = this.dragState.startLeft + deltaLeft;
// resizeProxy最终的位置
resizeProxy.style.left = Math.max(minLeft, proxyLeft) + "px";
};
const handleMouseUp = () => {
if (this.dragging) {
const { startColumnLeft, startLeft } = this.dragState;
const finalLeft = parseInt(resizeProxy.style.left, 10);
const columnWidth = finalLeft - startColumnLeft;
// column最终的宽度
column.width = column.realWidth = columnWidth;
this.store.scheduleLayout();
document.body.style.cursor = "";
this.dragging = false;
this.draggingColumn = null;
this.dragState = {};
table.resizeProxyVisible = false;
}
document.removeEventListener("mousemove", handleMouseMove);
document.removeEventListener("mouseup", handleMouseUp);
setTimeout(function () {
removeClass(columnEl, "noclick");
}, 0);
};
document.addEventListener("mousemove", handleMouseMove);
document.addEventListener("mouseup", handleMouseUp);
}
当鼠标按下移动时,监听mousemove事件,执行handleMouseMove函数,在鼠标松开时将计算后的width赋值给列的宽度,最终在DOM宽度上的改变是在store上的scheduleLayout函数
onColumnsChange
onColumnsChange(layout) {
const cols = this.$el.querySelectorAll("colgroup > col");
if (!cols.length) return;
const flattenColumns = layout.getFlattenColumns();
const columnsMap = {};
flattenColumns.forEach((column) => {
columnsMap[column.id] = column;
});
for (let i = 0, j = cols.length; i < j; i++) {
const col = cols[i];
const name = col.getAttribute("name");
const column = columnsMap[name];
if (column) {
col.setAttribute("width", column.realWidth || column.width);
}
}
},
这段代码好理解,获取到列后使用setAttribute设置列最终的宽度,至此列宽度更新完成