element-ui table 拖拽实现

Element-Ui Table 组件原本是不支持拖拽的,由于实际开发过程中有拖拽功能的需求,从开发角度上来说这种使用第三方组件库不支持然后自己加功能的方式有 Hack 的嫌疑,稍有不慎,代码就会越写越烂,日积月累导致项目爆炸💥,变得难以维护,如同破窗效应。

Table 支持拖拽功能

vuedraggable 是一个拖拽类组件,底层是他们的 Sortable 库,有老外对此封装了一个 NPM Package,根据实际情况取舍是 copy 一个文件还是 install 一个包。

使用下面的代码作为一个组件引入, handle 指定具体的 DOM 元素可拖拽,用于防止 input 无法鼠标选中的情况。

<template>
  <div ref="wrapper">
    <div :key="tableKey">
      <slot />
    </div>
  </div>
</template>

<script>
import sortable from 'sortablejs'
export default {
  name: 'ElementUiElTableDraggable',
  props: {
    handle: {
      type: String,
      default: ''
    },
    animate: {
      type: Number,
      default: 100
    }
  },
  data () {
    return {
      tableKey: 0
    }
  },
  watch: {
    tableKey () {
      this.$nextTick(() => {
        this.makeTableSortAble()
        this.keepWrapperHeight(false)
      })
    }
  },
  mounted () {
    this.makeTableSortAble()
  },
  methods: {
    makeTableSortAble () {
      const table = this.$children[0].$el.querySelector(
        '.el-table__body-wrapper tbody'
      )
      sortable.create(table, {
        handle: this.handle,
        animation: this.animate,
        onEnd: ({ newIndex, oldIndex }) => {
          this.keepWrapperHeight(true)
          this.tableKey = Math.random()
          const arr = this.$children[0].data
          const targetRow = arr.splice(oldIndex, 1)[0]
          arr.splice(newIndex, 0, targetRow)
          this.$emit('drop', { targetObject: targetRow, list: arr })
        }
      })
    },
    keepWrapperHeight (keep) {
      // eslint-disable-next-line prefer-destructuring
      const wrapper = this.$refs.wrapper
      if (keep) {
        wrapper.style.minHeight = `${wrapper.clientHeight}px`
      } else {
        wrapper.style.minHeight = 'auto'
      }
    }
  }
}
</script>

el-form-item 拖拽

watch: {
  uuid () {
    this.$nextTick(() => {
      this.makeTableSortAble()
      this.keepWrapperHeight(false)
    })
  }
},
mounted () {
  this.makeTableSortAble()
}



makeTableSortAble () {
  const table = document.querySelector(
    '.edit-nested-drag'
  )
  sortable.create(table, {
    handle: '.el-form-item__label',
    animation: 100,
    onEnd: ({ newIndex, oldIndex }) => {
      this.keepWrapperHeight(true)
      this.uuid = Math.random()
      const targetRow = this.config.tabList.splice(oldIndex, 1)[0]
      this.config.tabList.splice(newIndex, 0, targetRow)
      // this.$emit('drop', { targetObject: targetRow, list: this.config.tabList })
    }
  })
},
keepWrapperHeight (keep) {
  // eslint-disable-next-line prefer-destructuring
  const wrapper = document.querySelector(
    '.edit-nested-drag'
  )
  if (keep) {
    wrapper.style.minHeight = `${wrapper.clientHeight}px`
  } else {
    wrapper.style.minHeight = 'auto'
  }
}