vue自定义表格列的实现过程记录

目录
  • 前言
  • 效果图
  • setTable组件
  • 使用
  • 结束语

前言

在我们开发PC端的项目使用表单时,尤其是crm系统,应该经常会遇到这样的需求, 用户需要根据设置来自定义显示列。 查了element的官方文档, 并没有此类组件, 所以手动封装了一个简单的组件, 希望能在大家开发此类需求时能够有所帮助。

效果图

具体效果图如下:

自定义显示列  (可实现拖拽进行排序,点击选中,再次点击取消选中)

按照用户已设置好的字段排序/显示/隐藏每一列

setTable组件

首先实现拖拽排序的话我们需要借助一个插件:

npm install vuedraggable -S

具体的组件代码如下, 代码内已写有详细的注释,在这里就不过多赘述了。。

setTable.vue

<template>
  <div>
    <el-dialog title="自定义显示列" :visible.sync="dialogVisible" width="50%">
      <div class="select-menus menus-box">
        <p class="menus-title">拖动区块调整显示顺序</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">选择显示列</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">取 消</el-button>
        <el-button type="primary" @click="onSave">确 定</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: [],//全部菜单
      selected: [],//已选中菜单
    };
  },
  watch: {
    selected: {
      handler(oldVal, newVal) {
        if (this.fields.length === 0) {
          return;
        }
        newVal.map((i) => {
          this.fields.map((j) => {
            if (i.field === j.field) {
              // 如果已选中数组内已有相同字段, 则active为true。active主要用来控制全部菜单选中/未选中的样式
              j.active = true;
            }
          });
        });
      },
    },
  },
  mounted() {
    //为了防止火狐浏览器拖拽的时候以新标签打开
    document.body.ondrop = function (event) {
      event.preventDefault();
      event.stopPropagation();
    };
  },
  methods: {
    async getData() {
      // 获取全部菜单数据
      const { data: fields } = await getFields({
        types: this.types,
      });
      fields.map((item) => {
        // 由于服务器并没有返回active字段, 为此需要每一条数据增加active字段, 来控制选中的样式
        item.active = false;
      });
      this.fields = fields;
    },
    async getFields() {
      // 获取用户已选中的菜单, 为了再次打开设置时能够把上次选中菜单回显到页面,方便用户再次修改
      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() {
      // 保存已选中菜单
      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(); //刷新页面
    },
    async open() {
      // 打开设置窗口时清空数据,并再次请求获取最新数据
      this.fields = [];
      this.selected = [];
      this.dialogVisible = true;
      await this.getData();
      await this.getFields();
    },
    onSelect(item) {
      // 判断已选中菜单内是否已有点击选择的菜单
      let findex = this.selected.findIndex((i) => {
        return item.field === i.field;
      });
      if (findex === -1) {
        // 如果已选中菜单内没有, 则添加到最后一条
        this.selected.push(item);
      } else {
        // 如果已选中已有,则点击时应该对其移除,并把active设置为false, 改变其选中的样式
        item.active = false;
        this.selected.splice(findex, 1);
      }
    },
    datadragEnd(evt) {
      // 拖动排序
      evt.preventDefault();
    },
  },
};
</script>
<style lang="scss" scoped>
/* 全部菜单 */
.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;
    }
  }
}
/* 菜单通用样式 */
.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;
    }
  }
}

/* 已选菜单 */
.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>

使用

具体使用如下, 在这里已经隐去不必要的业务代码, 只把最核心实现的代码贴了出来, 以免对大家产生误导..

<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">暂无</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">暂无</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 ? '未跟进' : '已跟进' }}</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="操作" min-width="8%;">
        <template slot-scope="scope">
          <el-button @click="handleRead(scope.row)" type="text">详情</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>

在这里其实也可以设置成固定的列宽或者通过服务器返回具体的尺寸, 这样的话就不用写这么多的if语句了, 会更加方便简洁..

结束语

其实刚接到这个需求时,感觉挺复杂的, 尤其是需要进行拖动, 还要根据服务器返回不同的字段来进行表单列的排序。  但整体做下来并没有我想象的那么麻烦。 大家在遇到需求时, 也一定不要一直想的太多, 一定要先去尝试, 说不定它并没有你想的那么难..

到此这篇关于vue自定义表格列的文章就介绍到这了,更多相关vue自定义表格列内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Vue+Element自定义纵向表格表头教程

    如下所示: 代码如下: <table style="width: 100%" class="myTable"> <tr v-for="(item,i) in statDatas" :key="i"> <td class="column">{{ item.key }}</td> <td class="column">{{ item

  • vue自定义表格列的实现过程记录

    目录 前言 效果图 setTable组件 使用 结束语 前言 在我们开发PC端的项目使用表单时,尤其是crm系统,应该经常会遇到这样的需求, 用户需要根据设置来自定义显示列. 查了element的官方文档, 并没有此类组件, 所以手动封装了一个简单的组件, 希望能在大家开发此类需求时能够有所帮助. 效果图 具体效果图如下: 自定义显示列  (可实现拖拽进行排序,点击选中,再次点击取消选中) 按照用户已设置好的字段排序/显示/隐藏每一列 setTable组件 首先实现拖拽排序的话我们需要借助一个插

  • Vue项目打包部署的实战过程记录

    目录 前言 一.准备工作--服务器和nginx使用 1. 准备一台服务器 2. nginx安装和启动 3. 了解nginx: 修改nginx配置,让nginx服务器代理我们创建的文件 二.Vue项目打包同步文件到远程服务器 1. 打包 2. 同步到远程服务器 3. 同步ssh key 三.非域名根路径发布 1. nginx配置 2. 项目配置 3. 绝对路径引用的静态资源找不到的问题 四.history模式部署 1. 项目配置 2. nginx配置 3. history模式部署到非域名根路径下

  • vue实现自定义表格工具扩展

    本文实例为大家分享了vue自定义表格工具扩展的具体代码,供大家参考,具体内容如下 工具组件 <template>     <div class="right-btn">         <el-row>             <el-tooltip                 effect="dark"                 :content="showSearch ? '隐藏搜索' : '显示搜索

  • Vue Element Sortablejs实现表格列的拖拽案例详解

    1. css:    dragTable.css @charset "UTF-8"; .w-table{ height: 100%; width: 100%; float: left; } /* 拖动过程中,鼠标显示样式 */ .w-table_moving .el-table th .thead-cell{ cursor: move !important; } .w-table_moving .el-table__fixed{ cursor: not-allowed; } .w-ta

  • Vue 固定头 固定列 点击表头可排序的表格组件

    原理是将原table的指定行,指定列clone一份放在其上 实现代码如下: <template> <div> <div id="divBox1" :style="{height:height}"> <table id="tbTest1" cellpadding="0" cellspacing="0" style="text-align:center;bac

  • vue中使用protobuf的过程记录

    由于目前公司采用了ProtoBuf做前后端数据交互,进公司以来一直用的是公司大神写好的基础库,完全不了解底层是如何解析的,一旦报错只能求人,作为一只还算有钻研精神的猿,应该去了解一下底层的实现,在这里记录一下学习过程. Protobuf简单介绍 Google Protocol Buffer(简称 Protobuf)是一种轻便高效的结构化数据存储格式,平台无关.语言无关.可扩展,可用于通讯协议和数据存储等领域. 有几个优点: 1.平台无关,语言无关,可扩展: 2.提供了友好的动态库,使用简单; 3

  • VUE table表格动态添加一列数据,新增的这些数据不可以编辑(v-model绑定的数据不能实时更新)

    一.问题 用elementUi横着增加一行数据没毛病,可以操作 添加一列,这新增的这一列, 第一次去赋值的时候值是改了, 但没生效 点击下一行时 值就变过来 二.原因 横向添加 是复制上面的某一条数据来的,因为data里面有这些属性的定义,所以横向添加没问题 而纵向添加的数据,因为没有事先在 el-select v-modle="" 里面定义好字段,定义好的option是通过v-for出来的(option是写死的就不会有这个问题),就会出现选择后,select元素上无法展示,但是其实数

  • Vue实现动态控制表格列的显示和隐藏

    本文实例为大家分享了Vue实现动态控制表格列的显示和隐藏的具体代码,供大家参考,具体内容如下 效果如图: 表头标题是重复的.为了能看到滚动效果 v-if=“lists[0].ispass” 来判断表格列的状态每一列是否显示或隐藏 勾选则展示.取消勾选隐藏.默认勾选 <el-dropdown :hide-on-click="false">             <i class="iconfont icon-shaixuan" ></i

  • vue+elementui实现动态控制表格列的显示和隐藏

    vue+elementui(table,多选框)实现动态控制表格列的显示和隐藏,供大家参考,具体内容如下 imdex.vue <template>   <div>     <div>       <el-table :data="tableData" border style="width: 100%" ref="table">         <el-table-column prop=&q

  • vue实现动态控制el-table表格列的展示与隐藏

    本文实例为大家分享了vue动态控制el-table表格列的展示与隐藏的具体代码,供大家参考,具体内容如下 1.引入el-table组件,这里我直接用官网的示例代码 <template>     <div class="page">         <el-popover width="60" trigger="click">             <el-checkbox-group v-model=&

随机推荐