基于el-table封装的可拖拽行列、选择列组件的实现

效果

基于el-table封装的可拖拽行列、选择列组件的实现

需要环境

vue
elementUI
拖拽插件Sortable.js

需配置属性

基于el-table封装的可拖拽行列、选择列组件的实现

示例

<HTable
  :columns=\"columns\"
  :data=\"list\"
  :setColumn=\"true\"
  tableKey=\"CategoriesList\"
  style=\"width: 100%\"
  border
>
  // 这里可以放插槽
  <template slot=\"create_time\" slot-scope=\"scope\">
    {{ scope.column.label + scope.item.prop }}
  </template>
  <template slot=\"action\" slot-scope=\"scope\">
    <el-button type=\"primary\" @click=\"handleEdit(scope.row)\" size=\"small\">
      编辑
    </el-button>
    <el-button @click=\"handleDelete(scope.row)\" type=\"danger\" size=\"small\">
      删除
    </el-button>
  </template>
</HTable>
import HTable from \"@/components/HTable\";

export default {
  components: { HTable },
  data() {
    return {
      list: [],
      columns: [
        {
          label: \"ID\", // 描述
          prop: \"_id\", // 列的唯一值。 必须要有
          checked: true // 是否展示该列
          ... // 一些el-table-column的属性都可以写在这里
        },
        {
          label: \"分类名称\",
          prop: \"name\",
          checked: true
        },
        {
          label: \"上级分类\",
          prop: \"parent.name\",
          checked: true
        },
        {
          label: \"状态\",
          prop: \"status\",
          width: \"100\",
          checked: true
        },
        {
          label: \"创建时间\",
          prop: \"create_time\",
          slotHeaderName: \"create_time\", // 自定义表头
          checked: true
        },
        {
          label: \"操作\",
          prop: \"action\",
          fixed: \"right\",
          \"min-width\": \"100\",
          slotName: \"action\", // 自定义单元格插槽
          checked: true,
          disabled: true
        }
      ]
    };
  }
};

有用到的话给我点个赞!附组件代码

<template>
  <div class=\"HTable\">
    <div class=\"settingBox\" v-if=\"setColumn\">
      <el-popover
        placement=\"bottom-end\"
        trigger=\"click\"
        popper-class=\"settingPopper\"
      >
        <el-checkbox-group
          v-model=\"selectCol\"
          @change=\"handleChangeSelectColumn\"
        >
          <el-checkbox
            v-for=\"item in col\"
            :key=\"item.prop\"
            :label=\"item.prop\"
            :disabled=\"item.disabled\"
            style=\"display:block;line-height:2;margin-right:0;\"
            >{{ item.label }}</el-checkbox
          >
        </el-checkbox-group>
        <i class=\"icon el-icon-setting\" slot=\"reference\"></i>
      </el-popover>
    </div>
    <el-table
      v-bind=\"$attrs\"
      :data=\"tableData\"
      v-on=\"$listeners\"
      :key=\"JSON.stringify(checkedCol)\"
    >
      <el-table-column
        v-for=\"(item, index) in checkedCol\"
        :key=\"item.prop\"
        v-bind=\"item\"
        :index=\"index\"
        :column-key=\"item.prop\"
      >
        <template v-if=\"item.slotHeaderName\" v-slot:header=\"scope\">
          <slot :name=\"item.slotHeaderName\" v-bind=\"scope\" :item=\"item\"></slot>
        </template>
        <template v-if=\"item.slotName\" v-slot:default=\"scope\">
          <slot :name=\"item.slotName\" v-bind=\"scope\"></slot>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>

<script>
import Sortable from \"sortablejs\";
export default {
  name: \"HTable\",
  props: {
    tableKey: String,
    columns: {
      type: Array,
      default() {
        return [];
      }
    },
    data: {
      type: Array,
      default() {
        return [];
      }
    },
    setColumn: {
      type: Boolean,
      default: false
    }
  },
  watch: {
    columns: {
      handler(newVal) {
        let localVal = this.getStorageCol();
        let hotVal = [];
        if (localVal) {
          hotVal = this.dataDiff(newVal, localVal);
        } else {
          hotVal = [...newVal];
        }
        this.col = hotVal.map(
          (item, index) =>
            (item = { ...item, index, checked: item.checked || false })
        );
        this.checkedCol = this.checkedColFun(this.col);
        this.selectCol = this.checkedCol.map(item => (item = item.prop));
      },
      immediate: true
    },
    data: {
      handler(newVal) {
        this.tableData = [...newVal];
      },
      immediate: true
    },
    col: {
      handler(newVal) {
        this.setStorageCol(newVal);
      },
      deep: true,
      immediate: true
    }
  },
  data() {
    return {
      tableData: [],
      col: [],
      checkedCol: [],
      selectCol: []
    };
  },

  mounted() {
    document.body.ondrop = function(event) {
      event.preventDefault();
      event.stopPropagation();
    };
    this.$nextTick(() => {
      this.rowDrop();
      this.columnDrop();
    });
  },
  methods: {
    drap() {
      this.$nextTick(() => {
        this.rowDrop();
        this.columnDrop();
      });
    },

    handleChangeSelectColumn() {
      this.col.forEach(item => {
        if (this.selectCol.includes(item.prop)) {
          item.checked = true;
        } else {
          item.checked = false;
        }
      });
      this.checkedCol = this.checkedColFun(this.col);
      this.drap();
    },

    rowDrop() {
      const tbody = document.querySelector(\".el-table__body-wrapper tbody\");
      Sortable.create(tbody, {
        onEnd: ({ newIndex, oldIndex }) => {
          [this.tableData[newIndex], this.tableData[oldIndex]] = [
            this.tableData[oldIndex],
            this.tableData[newIndex]
          ];
          this.drap();
          this.$emit(\"dropRow\", {
            drapRow: this.tableData[oldIndex],
            targetRow: this.tableData[newIndex],
            drapRowIndex: oldIndex,
            targetRowIndex: newIndex,
            data: this.tableData
          });
        }
      });
    },
    columnDrop() {
      const wrapperTr = document.querySelector(\".el-table__header-wrapper tr\");
      Sortable.create(wrapperTr, {
        animation: 180,
        delay: 0,
        onEnd: ({ newIndex, oldIndex }) => {
          const oldItem = this.checkedCol[oldIndex];
          const newItem = this.checkedCol[newIndex];
          [this.col[newItem.index].index, this.col[oldItem.index].index] = [
            oldItem.index,
            newItem.index
          ];
          this.col.sort((a, b) => {
            return a.index - b.index;
          });
          this.checkedCol = this.checkedColFun(this.col);
          this.tableData = this.tableData.slice(0, this.tableData.length);
          this.drap();
          this.$emit(\"dropCol\", {
            colItem: oldItem,
            newIndex: newIndex,
            oldIndex: oldIndex,
            column: this.checkedCol
          });
        }
      });
    },
    checkedColFun(arr) {
      return arr.filter(item => item.checked);
    },
    setStorageCol(data) {
      if (this.tableKey && data && data.length > 0) {
        localStorage.setItem(\"HTable-\" + this.tableKey, JSON.stringify(data));
      }
    },
    getStorageCol() {
      let datajson = localStorage.getItem(\"HTable-\" + this.tableKey);
      return datajson ? JSON.parse(datajson) : \"\";
    },
    dataDiff(newVal, localVal) {
      let nl = newVal.length;
      let ll = localVal.length;
      if (nl != ll) {
        return newVal;
      } else {
        let np = newVal.map(item => item.prop).sort();
        let lp = localVal.map(item => item.prop).sort();
        if (np.join() != lp.join()) {
          return newVal;
        } else {
          let nnl = [];
          for (let i = 0; i < localVal.length; i++) {
            const item_l = localVal[i];
            for (let j = 0; j < newVal.length; j++) {
              const item_n = newVal[j];
              if (item_l.prop === item_n.prop) {
                nnl.push({
                  ...item_n,
                  index: item_l.index
                });
              }
            }
          }
          return nnl;
        }
      }
    }
  }
};
</script>

<style lang=\"less\" scoped>
.HTable {
  position: relative;
  .settingBox {
    width: 36px;
    height: 36px;
    border-radius: 2px;
    border: 1px solid #ebeef5;
    border-bottom: 0;
    margin-left: auto;
    position: relative;
    .icon {
      position: absolute;
      top: 0;
      left: 0;
      z-index: 1;
      width: 36px;
      height: 36px;
      text-align: center;
      font-size: 20px;
      line-height: 36px;
      color: #909399;
      cursor: pointer;
    }
  }
}
</style>
<style lang=\"less\">
.settingPopper {
  min-width: 100px !important;
}
</style>

到此这篇关于基于el-table封装的可拖拽行列、选择列组件的实现的文章就介绍到这了,更多相关el-table 可拖拽行列内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持! 

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容