关于antd组件tabel与插件vue-draggable-resizable同时使用时,拉伸后触发排序事件的问题

3,986 阅读4分钟

一、使用目的:

有时我们表格的数据项目过多,使用横向滚动栏依然觉得滚动起来很麻烦,这时需求要求我们的表格头部宽度可以自动进行拉伸,改变宽度,自定义显示需要看的数据,这时我们就可以考虑使用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的具体使用可以参考相关文档,此处需要我们注意的是:
  1. Components参数:这个参数是用于我们通过vue-draggable-resizable插件渲染table的接口。
  2. Bordered参数:由于拉伸表格时我们需要表头的分界线拖拽,所以需要使用到该参数,为表格增加框线。
  3. 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])
        }
      }
    }
  }
},

在这里我们需要理解:

  1. header的cell函数专门用于我们的表头渲染
  2. Cell传入三个参数,h,props,children。其中h是一个渲染函数,及vue中的h()。Props指的是表格传给表头单元格的数据。其中包括了表格主键key,以及表格的整个实体。最后的children则是表格的子组件。
  3. 通过参数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;
}

四、注意事项

  1. 注意上述方法在vue2+antd1上使用,对于其他版本并不适配。
  2. 对于需要进行拉伸的列一定要设置他的宽度width
  3. 当宽度不足屏幕宽度时,拉伸某个表头可能会影像其他的表头单元格。
  4. 拉伸表头后,长度可能会超出表格宽度,需要设置table的scroll属性的x,防止出现表头和数据不对应的情况。