Vue custom table column implementation process record

Vue custom table column implementation process record

Preface

When we develop PC-side projects using forms, especially CRM systems, we should often encounter such requirements. Users need to customize the display columns according to the settings. I checked the official documentation of element and found no such component, so I manually encapsulated a simple component, hoping it will be helpful when you develop such needs.

Rendering

The specific effect diagram is as follows:

Customize display columns (you can drag and drop to sort, click to select, click again to cancel)

Sort/show/hide each column according to the fields set by the user

setTable component

First, to implement drag and drop sorting, we need to use a plug-in:

npm install vuedraggable -S

The specific component code is as follows. Detailed comments have been written in the code, so I will not go into details here. .

setTable.vue

<template>
  <div>
    <el-dialog title="Custom display column" :visible.sync="dialogVisible" width="50%">
      <div class="select-menus menus-box">
        <p class="menus-title">Drag the blocks to adjust the display order</p>
        <div class="menus-content">
          <draggable v-model="selected" @update="datadragEnd" :options="{animation:500}">
            <transition-group>
              <div v-for="menu in selected" :key="menu.field" class="drag-item item">{{menu.name}}</div>
            </transition-group>
          </draggable>
        </div>
      </div>
      <div class="menus-container menus-box" v-if="fields.length">
        <p class="menus-title">Select display columns</p>
        <div class="menus-content">
          <div
            class="item"
            :class="{active:menu.active}"
            v-for="menu of fields"
            :key="menu.field"
            @click="onSelect(menu)"
          >{{menu.name}}</div>
        </div>
      </div>
      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">Cancel</el-button>
        <el-button type="primary" @click="onSave">OK</el-button>
      </span>
    </el-dialog>
  </div>
</template>
<script>
import draggable from "vuedraggable";
import { getFields, setFields, getFieldControl } from "@/api/user";
export default {
  name: "setTable",
  inject: ["reload"],
  props: {
    types: String,
  },
  components:
    draggable,
  },
  data() {
    return {
      dialogVisible: false,
      fields: [], //All menus selected: [], //Selected menu};
  },
  watch:
    selected: {
      handler(oldVal, newVal) {
        if (this.fields.length === 0) {
          return;
        }
        newVal.map((i) => {
          this.fields.map((j) => {
            if (i.field === j.field) {
              // If the same field already exists in the selected array, active is true. Active is mainly used to control the selected/unselected style of all menus j.active = true;
            }
          });
        });
      },
    },
  },
  mounted() {
    //To prevent Firefox from opening a new tab when dragging document.body.ondrop = function (event) {
      event.preventDefault();
      event.stopPropagation();
    };
  },
  methods: {
    async getData() {
      // Get all menu data const { data: fields } = await getFields({
        types: this.types,
      });
      fields.map((item) => {
        // Since the server does not return the active field, it is necessary to add an active field to each piece of data to control the selected style item.active = false;
      });
      this.fields = fields;
    },
    async getFields() {
      // Get the menu selected by the user, so that the last selected menu can be echoed to the page when the settings are opened again, so that the user can modify it again. let fields = await getFieldControl({
        account_id: this.$store.state.user.token.account_id,
        userid: this.$store.state.user.token.userid,
        types: this.types,
      });
      this.$nextTick(() => {
        this.selected.push(...fields.data);
      });
    },
    async onSave() {
      // Save the selected menu await setFields({
        account_id: this.$store.state.user.token.account_id,
        userid: this.$store.state.user.token.userid,
        types: this.types,
        content: this.selected,
      });
      this.reload(); //Refresh the page},
    async open() {
      // Clear the data when opening the settings window, and request the latest data again this.fields = [];
      this.selected = [];
      this.dialogVisible = true;
      await this.getData();
      await this.getFields();
    },
    onSelect(item) {
      // Determine whether there is a selected menu in the selected menu let findex = this.selected.findIndex((i) => {
        return item.field === i.field;
      });
      if (findex === -1) {
        // If there is no selected item in the menu, add it to the last item this.selected.push(item);
      } else {
        // If it is already selected, it should be removed when clicked, and active should be set to false to change its selected style item.active = false;
        this.selected.splice(findex, 1);
      }
    },
    datadragEnd(evt) {
      // Drag sort evt.preventDefault();
    },
  },
};
</script>
<style lang="scss" scoped>
/* All menus */
.menus-container {
  margin-top: 20px;
  .menus-content {
    .item {
      color: #575757;
      background: rgba(238, 238, 238, 1);
      border: 1px solid rgba(220, 220, 220, 1);
      border-radius: 2px 0px 0px 2px;
    }
  }
}
/* Menu general style*/
.menus-box {
  .menus-title {
    margin-top: 10px;
    line-height: 32px;
  }
  .menus-content {
    display: flex;
    flex-wrap: wrap;
    .item {
      cursor: pointer;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      padding: 8px;
      margin: 10px;
      border-radius: 3px;
    }
    .active {
      color: #fff;
      background: rgba(72, 153, 229, 1);
      border-radius: 2px 0px 0px 2px;
    }
  }
}

/* Selected menu */
.select-menus {
  .menus-content {
    .item {
      margin: 0px;
      border-radius: 0;
      background: rgba(255, 255, 255, 1);
      border: 1px solid rgba(220, 220, 220, 1);
    }
  }
}
</style>

use

The specific usage is as follows. Unnecessary business codes have been hidden here, and only the core implementation codes are posted to avoid misleading everyone.

<template>
  <div>
    <el-table
      ref="multipleTable"
      :data="tableData"
      height="60vh"
      :row-class-name="tableRowClassName"
      @selection-change="handleSelectionChange"
      @row-click="handleRead"
    >
      <el-table-column type="selection" min-width="55px;"></el-table-column>
      <template v-for="(item,index) of fields">
        <el-table-column
          v-if="item.field==='name'"
          :key="index"
          :prop="item.field"
          :label="item.name"
          min-width="10%;"
          show-overflow-tooltip
        ></el-table-column>
        <el-table-column
          v-if="item.field==='gender'"
          :key="index"
          :prop="item.field"
          :label="item.name"
          min-width="8%;"
          show-overflow-tooltip
        >
          <template slot-scope="scope">{{scope.row.gender===1?'男':'女'}}</template>
        </el-table-column>
        <el-table-column
          v-if="item.field==='corp_full_name'"
          :key="index"
          :prop="item.field"
          :label="item.name"
          min-width="14%;"
          show-overflow-tooltip
        ></el-table-column>
        <el-table-column
          v-if="item.field==='corp_name'"
          :key="index"
          :prop="item.field"
          :label="item.name"
          min-width="12%;"
          show-overflow-tooltip
        ></el-table-column>
        <el-table-column
          v-if="item.field==='up_date'"
          :key="index"
          :prop="item.field"
          :label="item.name"
          min-width="14%;"
          show-overflow-tooltip
        ></el-table-column>
        <el-table-column
          v-if="item.field==='position'"
          :key="index"
          :prop="item.field"
          :label="item.name"
          min-width="10%;"
          show-overflow-tooltip
        ></el-table-column>
        <el-table-column
          v-if="item.field==='remark_mobiles'"
          :key="index"
          :prop="item.field"
          :label="item.name"
          min-width="14%;"
          show-overflow-tooltip
        ></el-table-column>
        <el-table-column
          v-if="item.field==='source_name'"
          :key="index"
          :prop="item.field"
          :label="item.name"
          min-width="10%;"
          show-overflow-tooltip
        ></el-table-column>
        <el-table-column
          v-if="item.field==='address'"
          :key="index"
          :prop="item.field"
          :label="item.name"
          min-width="10%;"
          show-overflow-tooltip
        ></el-table-column>
        <el-table-column
          v-if="item.field==='detail_address'"
          :key="index"
          :prop="item.field"
          :label="item.name"
          min-width="10%;"
          show-overflow-tooltip
        ></el-table-column>
        <el-table-column
          v-if="item.field==='description'"
          :key="index"
          :prop="item.field"
          :label="item.name"
          min-width="10%;"
          show-overflow-tooltip
        ></el-table-column>
        <el-table-column
          v-if="item.field==='remark'"
          :key="index"
          :prop="item.field"
          :label="item.name"
          min-width="10%;"
          show-overflow-tooltip
        ></el-table-column>
        <el-table-column
          v-if="item.field==='recordContent'"
          :key="index"
          :prop="item.field"
          :label="item.name"
          min-width="14%;"
          show-overflow-tooltip
        ></el-table-column>
        <el-table-column
          v-if="item.field==='owner_name'"
          :key="index"
          :prop="item.field"
          :label="item.name"
          min-width="10%;"
          show-overflow-tooltip
        ></el-table-column>
        <el-table-column
          v-if="item.field==='follow_time'"
          :key="index"
          :prop="item.field"
          :label="item.name"
          min-width="8%;"
          show-overflow-tooltip
        >
          <template slot-scope="scope">
            <div v-if="scope.row.follow_time===scope.row.createtime">None</div>
            <div v-else>{{scope.row.follow_time | formatDate}}</div>
          </template>
        </el-table-column>
        <el-table-column
          v-if="item.field==='next_follow_time'"
          :key="index"
          :prop="item.field"
          :label="item.name"
          min-width="8%;"
          show-overflow-tooltip
        >
          <template slot-scope="scope">
            <div v-if="scope.row.next_follow_time===0">None</div>
            <div v-else>{{scope.row.next_follow_time | formatDate}}</div>
          </template>
        </el-table-column>
        <el-table-column
          v-if="item.field==='createtime'"
          :key="index"
          :prop="item.field"
          :label="item.name"
          min-width="8%;"
          show-overflow-tooltip
        >
          <template slot-scope="scope">
            <div>{{scope.row.createtime | formatDate}}</div>
          </template>
        </el-table-column>
        <el-table-column
          v-if="item.field==='updatetime'"
          :key="index"
          :prop="item.field"
          :label="item.name"
          min-width="8%;"
          show-overflow-tooltip
        >
          <template slot-scope="scope">
            <div>{{scope.row.updatetime | formatDate}}</div>
          </template>
        </el-table-column>
        <el-table-column
          v-if="item.field==='is_record'"
          :key="index"
          :prop="item.field"
          :label="item.name"
          min-width="10%;"
          show-overflow-tooltip
        >
          <template slot-scope="scope">
            <div>{{scope.row.is_record === 0 ? 'Not followed up' : 'Already followed up' }}</div>
          </template>
        </el-table-column>
        <el-table-column
          v-if="item.field==='if_record'"
          :key="index"
          :prop="item.field"
          :label="item.name"
          min-width="10%;"
          show-overflow-tooltip
        ></el-table-column>
      </template>
      <el-table-column label="Operation" min-width="8%;">
        <template slot-scope="scope">
          <el-button @click="handleRead(scope.row)" type="text">Details</el-button>
        </template>
      </el-table-column>
      <el-table-column align="right" min-width="4%;">
        <template slot="header">
          <i class="iconfont icongengduo" @click="onMore"></i>
        </template>
      </el-table-column>
    </el-table>
    <set-table ref="setting" types="leads"></set-table>
  </div>
</template>

<script>
import setTable from "@/components/setTable";
import { getFieldControl } from "@/api/user";
export default {
  name: "clues",
  components:
    setTable,
  },
  data() {
    return {
      fields: [],
    };
  },
  async mounted() {
    await this.getFields();
    this.clues();
  },
  methods: {
    async getFields() {
      let fields = await getFieldControl({
        account_id: this.$store.state.user.token.account_id,
        userid: this.$store.state.user.token.userid,
        types: "leads",
      });
      this.fields = fields.data;
    },
    onMore() {
      this.$refs.setting.open();
    },
  },
};
</script>

In fact, you can also set a fixed column width here or return the specific size through the server. In this way, you don’t need to write so many if statements, which will be more convenient and concise.

Conclusion

In fact, when I first received this requirement, it felt quite complicated, especially because it required dragging and sorting the form columns according to different fields returned by the server. But overall it wasn't as troublesome as I thought. When you encounter a need, don't think too much, be sure to try it first, maybe it's not as difficult as you think.

This is the end of this article about vue custom table columns. For more relevant vue custom table columns, please search 123WORDPRESS.COM’s previous articles or continue to browse the following related articles. I hope everyone will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • VUE2.0+ElementUI2.0 table el-table implements header extension el-tooltip
  • Vue+Element Custom Vertical Table Header Tutorial
  • Vue implements custom table tool extension

<<:  How Database SQL SELECT Queries Work

>>:  Detailed graphic explanation of installing MySQL database and configuring Java project on Linux

Recommend

Summary of pitfalls in virtualbox centos7 nat+host-only networking

Table of contents 1. Problem Background 2. What a...

A brief introduction to JavaScript arrays

Table of contents Introduction to Arrays Array li...

A complete example of implementing a timed crawler with Nodejs

Table of contents Cause of the incident Use Node ...

Linux kernel device driver kernel debugging technical notes collation

/****************** * Kernel debugging technology...

How to set Nginx to forward the domain name to the specified port

Enter /usr/local/nginx/conf sudo cd /usr/local/ng...

Detailed explanation of the use of JavaScript functions

Table of contents 1. Declare a function 2. Callin...

Detailed explanation of mysql permissions and indexes

mysql permissions and indexes The highest user of...

MySQL variable declaration and stored procedure analysis

Declaring variables Setting Global Variables set ...

Example code for element multiple tables to achieve synchronous scrolling

Element UI implements multiple tables scrolling a...

Parsing Linux source code epoll

Table of contents 1. Introduction 2. Simple epoll...

MySQL 5.7.19 (tar.gz) installation graphic tutorial under Linux

The first tutorial for installing MySQL-5.7.19 ve...

Detailed analysis and usage of tcpdump command under Linux

Introduction To put it simply, tcpdump is a packe...