低版本的antd table组件 官网文档上有可伸缩列功能,但是用起来有很明显的bug,无法直接拿来用;接下来给大家提供一个手写的拖拽方案:
1.首先,写好v-table组件,这里最重要的就是table组件中的‘components’属性,官方对component的描述是"覆盖默认的 table 元素",意思就是对table进行重写
<a-table :components="components" @change="handleTableChange" :columns="columns" :data-source="tableData" :rowKey="(record, index) => index" :pagination="false"></table>
2.然后用计算属性去定义这个components,这里的“ResizeHeader”就是重写table组件的一个方法,这里面还引入了‘customHeaderCell, ResizeColumnProvide’这两个方法后面会介绍
import ResizeHeader, { customHeaderCell, ResizeColumnProvide } from './header'computed: {components() {return {header: {cell: ResizeHeader,},}},}mixins: [ResizeColumnProvide],
3.我们创建一个header.js 文件 用来放ResizeHeader方法
//重构table组件的核心渲染函数const ResizeHeader = (h, props, children) => {const { key, column, ...restProps } = props;let content = [].concat(children);if (column?.resizable) {const handlerVNode = h(DragHandler, {props: {width: column.width,minWidth: Math.min(column.width, 100),column: column}}, []);content = content.concat(handlerVNode);}return h("th", {key,props: { column },...Object.assign({}, restProps, { class: (restProps.class || "") + " nio-header-th" })}, content);};
4.ResizeHeader方法里面“DragHandler”组件是对table组件重写后的一些拖拽操作的事件监听处理
const events = {start: "mousedown",move: "mousemove",stop: "mouseup",};//对table组件进行重构的核心方法组件const DragHandler = {name: "nio-drag-handler",//获取混入的方法(重新设置表头宽度)inject: {onResizeColumn: {default: noop}},props: {column: { type: Object, required: true },minWidth: { type: Number, required: true }},data() {return {dragging: false,thWidth: 0,// 列头的宽度,用于计算startX: 0,moveEvent: {remove: noop},stopEvent: {remove: noop}};},//销毁监听beforeDestroy() {this.removeEvents();},methods: {//鼠标开始拖拽handleMouseDown(e) {e.stopPropagation();e.preventDefault();this.handleStart(e);},handleStart(e) {this.dragging = true;this.removeEvents();this.thWidth = this.$el.parentNode.getBoundingClientRect().width;if (e instanceof MouseEvent && e.which !== 1) {return;}if (e.stopPropagation) e.stopPropagation();this.startX = e.pageX;this.moveEvent = addEventListenerWrap(document.documentElement, events.move, this.handleMove);this.stopEvent = addEventListenerWrap(document.documentElement, events.stop, this.handleStop);},handleMove(e) {this.updateWidth(e);},handleStop(e) {this.dragging = false;this.updateWidth(e);this.removeEvents();},updateWidth(e) {let pageX = e.pageX;const tmpDeltaX = this.startX - pageX;let w = Math.max(this.thWidth - tmpDeltaX, this.minWidth);w = Math.min(w, Infinity);this.onResizeColumn(w, this.column);},removeEvents() {this.moveEvent.remove();this.stopEvent.remove();}},//渲染div 绑定拖拽render(h) {const line = h("div", { class: "nio-drag-handler-line" }, []);return h("div", { class: "nio-drag-handler", on: { mousedown: this.handleMouseDown } }, [line]);}};//监听鼠标移动的方法function addEventListenerWrap(target, eventType, cb) {if (target && target.addEventListener) {target.addEventListener(eventType, cb);}return {remove: () => {if (target && target.removeEventListener) {target.removeEventListener(eventType, cb);}},};}
5.DragHandler组件中 最重要的方法是“onResizeColumn”方法,废话不多说 上代码
重点:ResizeColumnProvide 方法要以mixins混入的方式 引入到table组件的页面中,这样“DragHandler”就能用到this.onResizeColumn()方法,对列的宽度进行改变
//在table组件中混入的一个方法 provide => onResizeColumn //目的是在table重写中(DragHandler方法)//可以用到构造的onResizeColumn方法(重新设置表头的宽度)export const ResizeColumnProvide = {name: "ResizeColumnProvideMixin",provide() {return {onResizeColumn: this.onResizeColumn};},data() {const onResizeColumn = throttle2(this._resizeColumn, 30);return {columnsKey: "columns", //这个属性是table组件表头的集合名称 :columns="columns"moving:false, //这个属性是为了在拖拽时 阻止表头触发排序的功能onResizeColumn};},methods: {_resizeColumn(w, column) {const columns = this[this.columnsKey];this.moving = truelet time = setTimeout(() => {this.moving = falseclearTimeout(time)}, 2000);//在拖拽时找到对应表头 重新设置表头的宽度 //这就是为什么表头column要绑定customHeaderCell的原因 const matchedIndex = columns.findIndex(item => item.key === column.key);columns[matchedIndex].width = w;}}};
6.上面的方法中的‘throttle2’是对拖拽的一个节流操作
//拖拽的节流方法const throttle2 = (fn, delay) => {let valid = true;return (...args) => {if (!valid) {return;}valid = false;setTimeout(() => {fn(...args);valid = true;}, delay);};};
7.在第一步中 table组件 ,这里用到这个方法 是因为antd的table组件在用components属性进行重写时,无法获取到column(对应的表头数据),但是在拖拽的操作中,又需要拿到对应的表头数据,这里只能用table内置的customHeaderCell方法,在生成表头数据的时候,给每个表头数据绑定customHeaderCell方法
//table组件内置的一个方法export function customHeaderCell(column) {return Object.assign({column: column});}//给column绑定 不绑定的话ResizeHeader方法中的参数props无法获取到column信息 //这里的list 就是表头的集合this.columns = list.map((item) => Object.assign({}, item, { customHeaderCell }))
8.最后附加上css样式吧
.nio-header-th {position: relative;isolation: isolate;}.nio-drag-handler {position: absolute;right: 0;top: 0;height: 100%;width: 2px;z-index: 1;border: 1px dashed #eee;&:hover,&:focus {cursor: col-resize;border: 1px dashed #0bd9d9;}}