Implementation of draggable rows and columns and selection column components based on el-table encapsulation

Implementation of draggable rows and columns and selection column components based on el-table encapsulation

Effect

Need environment

vue
elementUI
Drag and drop plugin Sortable.js

Required configuration properties

Example

<HTable
  :columns="columns"
  :data="list"
  :setColumn="true"
  tableKey="CategoriesList"
  style="width: 100%"
  border
>
  // You can put slots here <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">
      Edit</el-button>
    <el-button @click="handleDelete(scope.row)" type="danger" size="small">
      Delete</el-button>
  </template>
</HTable>
import HTable from "@/components/HTable";

export default {
  components: { HTable },
  data() {
    return {
      list: [],
      columns: [
        {
          label: "ID", // description prop: "_id", // The unique value of the column. Must have checked: true // Whether to display this column... // Some el-table-column attributes can be written here},
        {
          label: "category name",
          prop: "name",
          checked: true
        },
        {
          label: "Superior Category",
          prop: "parent.name",
          checked: true
        },
        {
          label: "status",
          prop: "status",
          width: "100",
          checked: true
        },
        {
          label: "Creation time",
          prop: "create_time",
          slotHeaderName: "create_time", // Custom header checked: true
        },
        {
          label: "operation",
          prop: "action",
          fixed: "right",
          "min-width": "100",
          slotName: "action", // Custom cell slot checked: true,
          disabled: true
        }
      ]
    };
  }
};

Give me a thumbs up if it’s useful! Attached component code

<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>

This is the end of this article about the implementation of draggable rows and columns and selection column components based on el-table encapsulation. For more relevant el-table draggable rows and columns, please search for previous articles on 123WORDPRESS.COM or continue to browse the following related articles. I hope you will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • Detailed explanation of three ways to wrap text in el-table header
  • el-table in vue realizes automatic ceiling effect (supports fixed)
  • Vue+el-table realizes merging cells
  • vue perfectly realizes el-table column width adaptation
  • Secondary encapsulation of element el-table table (with table height adaptation)
  • vue uses sortable to implement el-table drag and drop sorting function
  • 4 ways to modify Element's el-table style in Vue
  • vue+element gets the subscript of a row in el-table and operates the array object according to the subscript
  • vue el-table implements custom table header
  • Vue el-table realizes inline editing function

<<:  【HTML element】How to embed images

>>:  Comprehensive summary of MYSQL tables

Recommend

How to find and delete duplicate records in MySQL

Hello everyone, I am Tony, a teacher who only tal...

A complete list of commonly used HTML tags and their characteristics

First of all, you need to know some characteristi...

Mysql 5.6 "implicit conversion" causes index failure and inaccurate data

background When performing a SQL query, I tried t...

Vue implements simple calculator function

This article example shares the specific code of ...

Solve the problem that the docker container cannot ping the external network

Today, when I was building a redis environment in...

Recommend 60 paging cases and good practices

<br />Structure and hierarchy reduce complex...

Drop-down menu and sliding menu design examples

I found a lot of websites that use drop-down or sl...

How to reduce the memory and CPU usage of web pages

<br />Some web pages may not look large but ...

JavaScript implements select all and unselect all operations

This article shares the specific code for JavaScr...

Detailed explanation of Linux copy and paste in VMware virtual machine

1. Linux under VMware Workstation: 1. Update sour...

Solve the compatibility issue between MySQL 8.0 driver and Alibaba Druid version

This article mainly introduces the solution to th...

Installation, configuration and use of process daemon supervisor in Linux

Supervisor is a very good daemon management tool....

Alibaba Cloud Server Tomcat cannot be accessed

Table of contents 1. Introduction 2. Solution 2.1...

Use image to submit the form instead of using button to submit the form

Copy code The code is as follows: <form method...