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

2022-09-20  本文已影响0人  二两毛豆

解决表头过多(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>
上一篇下一篇

猜你喜欢

热点阅读