Bootstrap

element-ui table组件实现可拖拽效果

最近接到一个表格拖拽并改变排序的需求
那么首先需要实现表格拖拽

一.引入第三方插件

1.引入sortable.js的包: npm install sortable.js --save
2.或者npm i -S vuedraggable
  vuedraggable依赖 Sortable.js,所以下载了vuedraggable,我们便可以直接引入Sortable使用Sortable的特性。
  vuedraggable是Sortable一种加强,实现组件化的思想,可以结合Vue,使用起来更方便

二.使用sortable

以sortable为例子,在我们需要使用sortable的文件中
import Sortable from 'sortablejs'

三.代码展示

如果要使用sortable,那么element table务必指定row-key,并且row-key必须是唯一的,如ID,不然会出现排序不对的情况,一般情况下浏览器会直接报错。

1.html布局
<el-table
   	size='small'
	:data='videoTable'
	style='width:100%'
	row-key='sn'
	@cell-mouse-enter.once='rowDrop'
	:row-class-name='rowClassName'
>
	<el-table-column width='50'>
		<i class='el-icon-s-operation' style='font-size: 14px'></i>
	</el-table-column>
	<el-table-column prop='ordering' label='序号' width='50' type='index'></el-table-column>
	<el-table-column prop='sn' label='内容ID' min-width='120'></el-table-column>
	<el-table-column prop='title' label='内容标题' min-width='120'></el-table-column>
	<el-table-column prop='fileSize' label='大小' min-width='80'>
		<template slot-scope='scope'>
			<span>{{ scope.row.fileSize }}M</span>
		</template>
	</el-table-column>
	<el-table-column min-width='80'>
		<template slot-scope='scope'>
			<el-button type='text' size='small' @click='deleteVideo(scope.row)'>删除</el-button>
		</template>
	</el-table-column>
</el-table>

因为需要,我代码中使用得是sn,但同id一样也是唯一的
因为要排序,所以应用了element-ui table组件的Table-column Attributes: type
type=index时,会通过传递index属性来自定义索引,从1开始,这样每次拖拽之后都会重新自动排序

2.核心js
//行拖拽
methods: {
    rowDrop() {
      const tbody = document.querySelector('.el-table__body-wrapper tbody')
      const self = this
      Sortable.create(tbody, {
        onEnd({ newIndex, oldIndex }) {
          const currRow = self.tableData.splice(oldIndex, 1)[0]
          self.tableData.splice(newIndex, 0, currRow)
        }
      })
    },
//列拖拽
    columnDrop() {
      const wrapperTr = document.querySelector('.el-table__header-wrapper tr')
      this.sortable = Sortable.create(wrapperTr, {
        animation: 180,
        delay: 0,
        onEnd: evt => {
          const oldItem = this.dropCol[evt.oldIndex]
          this.dropCol.splice(evt.oldIndex, 1)
          this.dropCol.splice(evt.newIndex, 0, oldItem)
        }
      })
    },
},
mounted() {
    this.rowDrop()
    this.columnDrop()
},
注意

在这里我遇到了一个问题,就是他会报出一个错误,大致原因就是因为table中的数组内容还未渲染完成就调用了拖拽的方法,没有el元素去支持这个方法的运行
这里我以拖拽行为例,因为我只用到了拖拽行,当我console.log(tbody)发现此时输出的并不是table的数据,而是null

解决方案

1.我使用的解决方案之一便是刚开始不调用拖拽的方法,使用el-table内置的方法@cell-mouse-enter.once='rowDrop'
当进入到表格的每一个column中都会触发这个方法,但是这样做会导致我们多次调用这个方法,浪费资源,所以这是需要once来让此方法只调用一次,如果不太懂once的作用可以去vue文档中看一下。
2.这个方法就更容易理解setTimeout,延缓一段时间再去执行,数据渲染的时间是很快的,所以设置的时间也不宜过长,我设置了300ms,虽然可能还不是最短时间,但是刚好也不会影响接下来的操作。

参考http://www.cnblogs.com/jin-zhe/p/10181852.html

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;