**红框的div为拖拽的手柄,是通过render进去的。可以看到有一个style样式 transform:translate(150px, 0)。这个150是怎么来的呢,150是表格column数据的width。而且这个div是相对th的绝对定位,left为 负的 手柄宽的一半这个很好理解吧。那么问题来了,这个column的width属性实际上设置的是min-width。也就是说当容器的宽度远大于表格所有column的width的和时,单元格的width会自适应撑开,拿这个150为例子 单元格的宽度不再是150了,而是适应容器后的大于150的一个数据。但是啊,这个resizeable插件并没有处理这种情况,所以translateX 一直是150,导致 拖拽的手柄不在期望的右border上 **
禁止 transform样式
left -10, 改为right -10 这样就ok了
.table-draggable-handle {
transform: none !important;
bottom: 0;
right: -10px !important;
cursor: col-resize;
touch-action: none;
position: absolute;
}
对照了一下官方,css居然都不一样,于是增加了第一个改动
因为style内联样式自带了 translate属性,所以直接去掉right:0;只留left -5.height设置100%就可以。
.resize-table-th {
position: relative;
.table-draggable-handle {
height: 100% !important;
bottom: 0;
left: -5px !important;
cursor: col-resize;
touch-action: none;
position: absolute;
}
}
于是又是检查了元素,发现th的width在变化,但是colGroup的width属性没有变。于是开启了寻找对应的colGroup的子元素col之旅,最后找到了,然后就是一顿操作在draging的时候同时修改了 colGroup的col的width属性。这样就可以跟着变化了。
查看代码发现当为固定列或者固定表头的情况下实际上thead和tbody是在不同的 table上,这时候就需要找到所有的colGroup测col,改变width。这样就处理了固定表头的拉伸。但是固定列的情况还是需要另外设置css ,找到table-fixed-left重新设置宽度。
根据当前的th,判断th是父元素的第几个孩子节点,对应到colGroup的第几个col节点
const loopDom = ss => {
if (ss.previousSibling !== null) {
thDomIndex++;
loopDom(ss.previousSibling);
}
};
function resetFixedColumns(width) {
const fixedHead = document.querySelector(".ant-table-fixed-left .ant-table-header");
const fixedBody = document.querySelector(".ant-table-fixed-left .ant-table-body-outer .ant-table-fixed");
if (fixedHead) {
fixedHead.style.width = width + "px";
fixedBody.style.width = width + "px";
}
}
递归遍历数组,获取宽度
getDraggingMap(tbCols, draggingMap) {
tbCols.forEach(col => {
if (col.children) {
this.getDraggingMap(col.children, draggingMap);
} else {
const key = col.dataIndex || col.key; //这儿要求表格数据中要有这两个属性
draggingMap[key] = col.width || 0;
}
});
},
递归遍历数组,获取当前列(这个递归真的很烦,不知道你们写递归是什么感受,
对了这里的this._.forEach 是lodash的写法, 因为原生forEach不会跳出循环)
// 处理多级表头
getRenderCoL(key, tbCols) {
let result = "";
this._.forEach(tbCols, item => {
if (item.children) {
result = this.getRenderCoL(key, item.children);
return !result;
} else {
const k = item.dataIndex || item.key;
if (k === key) {
result = item;
return false;
}
}
});
return result;
}
递归遍历数组, 获取多级表头操作列索引(同样难以忍受的递归,开始少了最后一个renturn 一直跑不对,递归的阴影面积正无穷)
const loopDom = (cols, col) => {
let tag = true;
this._.forEach(cols, co => {
if (co.dataIndex == col.dataIndex) {
thDomIndex++;
tag = false;
return tag;
}
if (co.children) {
tag = loopDom(co.children, col);
return tag;
} else {
thDomIndex++;
}
});
return tag;
};
这是一个js文件,通过mixin的方式引入table主文件, table 添加
:components="drag(columnKeys)"
//mixins/tableDragResize.js
//mixins/tableDragResize.js
import Vue from "vue";
import VueDraggableResizable from "vue-draggable-resizable";
Vue.component("vue-draggable-resizable", VueDraggableResizable);
export default {
data() {
return {
maxLevel: 1
};
},
methods: {
drag(columns) {
return {
header: {
cell: this.initDrag(columns)
}
};
},
/**
* @param { 表格columns } tbCols
*/
initDrag(tbCols) {
let draggingMap = {};
this.getDraggingMap(tbCols, draggingMap, 1);
let draggingState = Vue.observable(draggingMap);
return (h, props, children) => {
let thDomIndex = 0;
const { key, ...restProps } = props;
let col = {};
// 处理多级表头
col = this.getRenderCoL(key, tbCols);
if (!col || !col.width) {
//这儿要求表格数据中要有宽width属性,若是没有是不会执行下面的拖拽的
return {children} ;
}
const onDrag = x => {
col.width = Math.max(x, 1);
draggingState[key] = col.width;
thDomIndex = 0;
loopDom(tbCols, col);
// 自带复选框 列
if (!this.attrBute.isCheck) {
thDomIndex--;
}
let colgroup = document.querySelectorAll("colgroup");
colgroup.forEach(Element => {
let childCol = Element.children;
if (childCol[thDomIndex]) childCol[thDomIndex].style.width = col.width + "px";
});
// 固定列情况,resetFixedColumns中的参数 width 要经过计算得到整个变化后的table-fixed-left的宽度
if (col.fixed) this.resetFixedColumns(col.width + this.attrBute.isCheck ? 60 : 0);
};
const loopDom = (cols, col) => {
let tag = true;
this._.forEach(cols, co => {
if (co.dataIndex == col.dataIndex) {
thDomIndex++;
tag = false;
return tag;
}
if (co.children) {
tag = loopDom(co.children, col);
return tag;
} else {
thDomIndex++;
}
});
return tag;
};
const onDragstop = () => {};
let helper;
if (col.helper) {
helper = {this.$slots[col.dataIndex + "_helper"]};
}
return (
{children}
{helper}
);
};
},
getheadT(d) {
return d.newTitle;
},
getheadTis(d) {
return d.tips;
},
getResizableHandler(col) {
// let baseH = thDom.getBoundingClientRect().height;
// 单元格size
let size = this.cellsize ? this.cellsize : this.attrBute.cellsize;
let baseH = size == "middle" ? 47 : size == "small" ? 39 : 55;
if (col.isEndNode) return baseH * col.nodeLevel;
else if (col.leafNode && col.nodeLevel < this.maxLevel) {
return baseH * this.maxLevel;
} else return baseH;
},
resetFixedColumns(width) {
const fixedHead = document.querySelector(".ant-table-fixed-left .ant-table-header");
const fixedBody = document.querySelector(".ant-table-fixed-left .ant-table-body-outer .ant-table-fixed");
if (fixedHead) {
fixedHead.style.width = width + "px";
fixedBody.style.width = width + "px";
}
},
getDraggingMap(tbCols, draggingMap, nodeLevel) {
tbCols.forEach((col, index) => {
col.nodeLevel = nodeLevel;
col.isEndNode = index == tbCols.length - 1;
this.maxLevel = Math.max(this.maxLevel, nodeLevel);
if (col.children) {
col.leafNode = false;
this.getDraggingMap(col.children, draggingMap, nodeLevel + 1);
} else {
col.leafNode = true;
const key = col.dataIndex || col.key; //这儿要求表格数据中要有这两个属性
draggingMap[key] = col.width || 0;
}
});
},
getRenderCoL(key, tbCols) {
let result = "";
this._.forEach(tbCols, item => {
if (item.children) {
result = this.getRenderCoL(key, item.children);
return !result;
} else {
const k = item.dataIndex || item.key;
if (k === key) {
result = item;
return false;
}
}
});
return result;
}
}
};
getDraggingMap(tbCols, draggingMap, nodeLevel) {
tbCols.forEach((col, index) => {
col.nodeLevel = nodeLevel;
col.isEndNode = index == tbCols.length - 1;
this.maxLevel = Math.max(this.maxLevel, nodeLevel);
if (col.children) {
col.leafNode = false;
this.getDraggingMap(col.children, draggingMap, nodeLevel + 1);
} else {
col.leafNode = true;
const key = col.dataIndex || col.key; //这儿要求表格数据中要有这两个属性
draggingMap[key] = col.width || 0;
}
});
},
首先去除css 中height :100%;
然后在render时 设置组件高度如下
h={this.getResizableHandler(col)}
size 是表格尺寸
getResizableHandler(col) {
// let baseH = thDom.getBoundingClientRect().height;
let size = this.cellsize ? this.cellsize : this.attrBute.cellsize;
let baseH = size == "middle" ? 47 : size == "small" ? 39 : 55;
if (col.isEndNode) return baseH * col.nodeLevel;
else if (col.leafNode && col.nodeLevel < this.maxLevel) {
return baseH * this.maxLevel;
} else return baseH;
},
说明:通过columns 增加helper字段来判断 标题是否自定义
if (col.helper) {
helper = {this.$slots[col.dataIndex + "_helper"]};
}
这个是调用时
AF_JFBZMX__BZIDNAME_helper
AF_JFBZMX__JFJSSX_helper
重写上面的 return 。
注意这里是jsx语法,所以slot 只能通过 this.$slots[col.dataIndex + “_helper”] 这个来取。
在jsx语法中不存在v-if 和v-for, 所以只能在前边先进行判断,再return。
let helper;
if (col.helper) {
helper = {this.$slots[col.dataIndex + "_helper"]};
}
return (
{children}
{helper}
);