一、使用目的:
有时我们表格的数据项目过多,使用横向滚动栏依然觉得滚动起来很麻烦,这时需求要求我们的表格头部宽度可以自动进行拉伸,改变宽度,自定义显示需要看的数据,这时我们就可以考虑使用vue-draggable-resizable插件,结合我们的table插件进行操作。
二、适用版本
适合我们使用antdUI框架2.0以下版本,需要实现表格头部可自定义宽度效果。
三、操作流程
1.使用antd框架画出基本的table组件
<a-table
:columns="headers"
:dataSource="dataSource"
:pagination="false"
rowKey="id"
bordered
:components="components"
:scroll="{y: wrapHeight - 440, x: 1500}"
onChange: onSelectChange"
></a-table>
- 关于a-table的具体使用可以参考相关文档,此处需要我们注意的是:
- Components参数:这个参数是用于我们通过vue-draggable-resizable插件渲染table的接口。
- Bordered参数:由于拉伸表格时我们需要表头的分界线拖拽,所以需要使用到该参数,为表格增加框线。
- Columns参数:a-table在判断两个列是否相等时有两种判断,一种是直接根据key判断,key相等则相等。另一种是判断两个col实体是否相等(前者先于后者)。由于拉伸后col的宽度发生了改变,所以我们需要使用第一种判断方式,因此需要设置排序列的key值。
2.设置components参数信息,规定表格渲染规则
由于一般我们表格会存在排序功能,表格信息随时可能会变化,所以我们的渲染规则components需要放如computed中去。
computed: {
components () {
return {
header: {
cell: (h, props, children) => {
const {key, ...restProps} = props
// 由于drag事件结束后必然会出发click事件,所以我们需要一个参数去判断当前操作是click点击事件还是drag拖拽事件
let isDrag = false
// 获取当前key值所对应的column信息
const col = this.headers.find(col => {
const k = col.dataIndex || col.key
return k === key
})
// 如果col没有设置宽度,则直接原样渲染回去,不添加拉伸表格功能
if (!col || !col.width) {
return h('th', {...restProps}, [...children])
}
// 如果存在宽度,则设置vue-draggable-resizable插件渲染参数,具体可以参考相关文档
const dragProps = {
key: col.dataIndex || col.key,
class: 'table-draggable-handle',
attrs: {
w: 10,
x: col.width,
z: 1,
axis: 'x',
draggable: true,
transform: 'none',
resizable: false
},
draggable: true,
resizable: false,
on: {
// 拖动时把isdrag参数设置为true
dragging: (x, y) => {
isDrag = true
col.width = Math.max(x, 40)
},
// 拖动结束后把isdrag参数设置为false
dragstop: () => {
isDrag = true
// eslint-disable-next-line vue/no-async-in-computed-properties
setTimeout(() => {
isDrag = false
}, 300)
}
}
}
// 取出column的click事件,对事件进行判断,如果现在isDrag参数为true,则截胡,防止拖动后触发click事件
if (restProps.on && restProps.on.click) {
let clickFunc = restProps.on.click
restProps.on.click = (event) => {
if (isDrag) {
return
}
clickFunc(event)
}
}
// 渲染vue-draggable-resizable插件到column中去,即可实现拖拽
const drag = h('vue-draggable-resizable', {...dragProps})
return h('th', {...restProps, class: 'resize-table-th'}, [...children, drag])
}
}
}
}
},
在这里我们需要理解:
- header的cell函数专门用于我们的表头渲染
- Cell传入三个参数,h,props,children。其中h是一个渲染函数,及vue中的h()。Props指的是表格传给表头单元格的数据。其中包括了表格主键key,以及表格的整个实体。最后的children则是表格的子组件。
- 通过参数isDrag判断当前操作是点击还是拖拽。拖拽完成后有一个setTimeout异步函数,用于防止拖拽刚完成,isDrag数据更新后触发到了click事件。
3.设置columns参数的sorter,通过watch监听sortOrder参数的变化
由于我们将components设定在了computed中,所以columns没有办法实现动态更新,而使用中sortOrder是需要及时变化的,所以我们单独使用watch实现columns的动态更新。
watch: {
sortedInfo () {
this.columns.forEach(item => {
if (item.sorter) item.sortOrder = this.sortedInfo && this.sortedInfo.columnKey === item.dataIndex && this.sortedInfo.order
})
}
},
4.添加相应的class
>>>.resize-table-th {
position: relative;
}
>>> .table-draggable-handle {
transform: none !important;
position: absolute;
height: 100% !important;
bottom: 0;
left: auto !important;
right: -5px;
cursor: col-resize;
touch-action: none;
}
四、注意事项
- 注意上述方法在vue2+antd1上使用,对于其他版本并不适配。
- 对于需要进行拉伸的列一定要设置他的宽度width
- 当宽度不足屏幕宽度时,拉伸某个表头可能会影像其他的表头单元格。
- 拉伸表头后,长度可能会超出表格宽度,需要设置table的scroll属性的x,防止出现表头和数据不对应的情况。