element 表格拖拽排序与动态表头

解决表头过多(20+)表格数据展示不直观的问题。

产品功能

1.隐藏不重要的表头
2.表头拖拽排序
3.可设置默认显示n个表头
4.自定义设置不可关闭的表头

实现效果

image.png

实现代码

为了对组件的解耦故对组件进行了拆分

主页面
<template>
  <div class="sc">
    <sctable :productList="productList" :defaultColumns="defaultColumns">
      <headerBtn
        slot="customizeBtn"
        :defaultColumns="defaultColumns"
        @customizeHeader="(val) => (defaultColumns = val)"
      ></headerBtn>
    </sctable>
  </div>
</template>
<script>
export default {
  components: {
    headerBtn: require("./module/headerBtn.vue").default,
    sctable: require("./module/table.vue").default,
  },
  props: {},
  data() {
    return {
      productList: [
        {
          productNo: "产品编号",
          customerProductNo: "客户产品编号",
          name: "笔记本",
          englishName: "macBook",
          productLabel: "产品标签",
          logisticsLabel: "物流标签",
          productClassify: "产品分类",
          salesman: "销售",
          buyer: "采购",
          tradeMode: "贸易方式",
        }
      ],
      //编辑后的表头
      defaultColumns: [
        { label: "中文名称", prop: "name" },
        { label: "英文名称", prop: "englishName" },
        { label: "产品编号", prop: "productNo" },
        { label: "客户产品编号", prop: "customerProductNo" },
        { label: "产品标签", prop: "productLabel" },
        { label: "物流标签", prop: "logisticsLabel" },
        { label: "产品分类", prop: "productClassify" },
        { label: "销售", prop: "salesman" },
        { label: "采购", prop: "buyer" },
        { label: "贸易方式", prop: "tradeMode" },
      ],
    };
  },
};
</script>

<style lang="scss" scoped>
.sc /deep/ {
  width: 1200px;
  height: 800px;
  background: #dcdfe6;
  margin: 20px auto;
  padding: 50px 10px;
  .set_row {
    text-align: right;
    margin: 10px 0;
  }
}
</style>
拖拽与动态显示(核心功能)
<template>
  <div class="customize_btn">
    <el-popover
      placement="bottom-end"
      popper-class="del_popover"
      title="表头显示"
      width="500"
      trigger="click"
      v-model="visible"
    >
      <el-divider content-position="center">拖拽排序</el-divider>
      <div class="tag_show">
        <ul class="tag_ul">
          <li
            class="tag_li"
            :key="tag.label"
            v-for="(tag, index) in beFacedHeader"
            draggable
            @dragenter="dragenter($event, index)"
            @dragover="dragover($event, index)"
            @dragstart="dragstart(index)"
          >
            {{ tag.label }}
            <i
              @click="handleClose(tag)"
              v-if="notDeleteArr.indexOf(tag.prop) == -1 ? true : false"
              class="el-icon-close"
            ></i>
          </li>
        </ul>
      </div>
      <el-divider v-if="newDefaultColumns.length" content-position="center"
        >选至上方显示,选至下方不显示</el-divider
      >
      <div v-if="newDefaultColumns.length" class="tag_show">
        <ul class="tag_ul">
          <li
            class="tag_li"
            :key="index"
            v-for="(tag, index) in newDefaultColumns"
          >
            {{ tag.label }}
            <i
              @click="handleCloseNew(tag)"
              v-if="notDeleteArr.indexOf(tag.prop) == -1 ? true : false"
              class="el-icon-close"
            ></i>
          </li>
        </ul>
      </div>

      <div style="overflow: hidden; margin: 0 5px" v-if="!isLiveUpdate">
        <div style="float: left; margin: 0; display: inline-block">
          <el-button
            class="search_txt_btn"
            size="mini"
            type="text"
            @click="reset"
            >重置</el-button
          >
        </div>
        <div style="float: right; margin: 0; display: inline-block">
          <el-button
            class="search_txt_btn"
            size="mini"
            type="text"
            @click="visible = false"
            >取消</el-button
          >
          <el-button
            class="tile_btn"
            type="primary"
            size="mini"
            @click="visible = false"
            >确定</el-button
          >
        </div>
      </div>

      <div slot="reference" class="set_row">
        <el-button class="set_btn" plain icon="el-icon-setting"
          >列表设置</el-button
        >
      </div>
    </el-popover>
  </div>
</template>
  
  <script>
export default {
  props: {
    // 是否实时更新
    isLiveUpdate: {
      type: Boolean,
      default: true,
    },
    // 不可被关闭的收起的数组
    notDeleteArr: {
      type: Array,
      default: () => ["productNo", "name"],
    },
    // 默认显示前5个表头
    defaultHeaderLength: {
      type: Number,
      default: 5,
    },
    //   表头
    defaultColumns: {
      type: Array,
      default: () => [],
    },
  },
  data() {
    return {
      dragIndex: "", //当前拖拽的元素下标
      visible: false,//浮窗状态
      beFacedHeader: [],// 显示的表头集合
      newDefaultColumns: [],//隐藏的表头集合
    };
  },
  created() {
    this.beFacedHeader = JSON.parse(JSON.stringify(this.defaultColumns));
    // 默认只显示前 'defaultHeaderLength' 个表头
    let arr1 = this.beFacedHeader.slice(0, this.defaultHeaderLength);
    let arr2 = this.beFacedHeader.slice(
      this.defaultHeaderLength,
      this.beFacedHeader.length
    );
    this.beFacedHeader = arr1;
    this.newDefaultColumns = arr2;
    this.$emit("customizeHeader", this.beFacedHeader);
  },
  mounted() {},
  methods: {
    dragstart(index) {
      this.dragIndex = index;
    },
    dragover(e, index) {
      e.preventDefault();
    },
    dragenter(e, index) {
      e.preventDefault();
      // 避免源对象触发自身的dragenter事件
      if (this.dragIndex !== index) {
        const source = this.beFacedHeader[this.dragIndex];
        this.beFacedHeader.splice(this.dragIndex, 1);
        this.beFacedHeader.splice(index, 0, source);
        // 排序变化后目标对象的索引变成源对象的索引
        this.dragIndex = index;
        this.$emit("customizeHeader", this.beFacedHeader);
      }
    },
    // 显示的表头
    handleClose(tag) {
      this.beFacedHeader.splice(this.beFacedHeader.indexOf(tag), 1);
      let newDefaultColumns = this.newDefaultColumns;
      newDefaultColumns.push(tag);
      this.newDefaultColumns = newDefaultColumns;
      this.$emit("customizeHeader", this.beFacedHeader);
    },
    // 隐藏的表头
    handleCloseNew(tag) {
      this.newDefaultColumns.splice(this.newDefaultColumns.indexOf(tag), 1);
      let beFacedHeader = this.beFacedHeader;
      beFacedHeader.push(tag);
      this.beFacedHeader = beFacedHeader;
      this.$emit("customizeHeader", this.beFacedHeader);
    },
  },
};
</script>
  
<style lang="scss" scoped>
.customize_btn {
  .set_btn {
    background: #fff;
    color: #000;
    border: 1px solid #dcdfe6;
  }
  .set_btn:hover,
  .set_btn:focus {
    background: #fff;
    color: #000;
    border: 1px solid #dcdfe6;
  }
}
.tag_ul {
  list-style: none;
  padding: 0;
  .tag_li {
    display: inline-block;
    font-size: 12px;
    background-color: #f4f4f5;
    border-color: #e9e9eb;
    color: #909399;
    margin: 3px 5px;
    height: 24px;
    padding: 0 8px;
    line-height: 22px;
    border-radius: 4px;
    border-width: 1px;
    border-style: solid;
    border-radius: 4px;
    box-sizing: border-box;
    white-space: nowrap;
    .el-icon-close {
      color: #909399;
      border-radius: 50%;
      text-align: center;
      position: relative;
      cursor: pointer;
      font-size: 12px;
      height: 16px;
      width: 16px;
      line-height: 16px;
      vertical-align: middle;
      top: 0px;
      right: -5px;
      transform: scale(0.8);
    }
    .el-icon-close:hover {
      color: #fff;
      background-color: #909399;
    }
  }
}
</style>
表格
<template>
  <div class="sc_table">
    <slot name="customizeBtn"></slot>
    <el-table
      ref="table"
      :data="productList"
      style="width: 100%"
      highlight-current-row
      class="primor_table_input table_sty"
      :header-cell-style="header_style"
      :row-style="tableRowStyle"
    >
      <el-table-column type="selection" fixed="left"></el-table-column>
      <el-table-column
        v-for="(item, index) in defaultColumns"
        :key="index"
        show-overflow-tooltip
        :prop="item.prop"
        :label="item.label"
        :width="item.width"
        :min-width="item.minWidth ? item.minWidth : '120'"
      >
        <template slot-scope="scope">
          {{ scope.row[item.prop] }}
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>
  
  <script>
export default {
  props: {
    //   数据源
    productList: {
      type: Array,
      default: () => [],
    },
    //   表头
    defaultColumns: {
      type: Array,
      default: () => [],
    },
  },
};
</script>
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容