el-table动态配置列

1,744 阅读1分钟

这个项目是一个管理后台,表格字段太多了,页面容纳不下,所以产品希望能增加一个用户设置表格字段的功能,自定义查看对应的参数,因为项目已经上线,所以希望能前端解决,缩短开发时间。

该项目基于vue-element-admin,感谢尤大大和花裤衩。

1. 设置是全局的,放vuex,然后根据路由来匹配当前页面的表格参数。

setting.gif

数据格式如下:

    userDefined: [
        {
          path: "/order/list", //路径,用来匹配当前页面
          list: [
            {
              label: "客户备注", //表格列名
              align: "center", //文字居中
              prop: "remark", //参数名
              isShow: true, //用来过滤列的,这个属于自定义,不是表格要的
            },
            ...省略,
            {
              label: "审核时间", //表格列名
              width: "140", //表格宽度
              align: "center",  //文字居中
              prop: "verifyTime", //参数名
              formatter: "formatTime", //表格内容格式化方法,因为列要用到循环,但是格式化方法不一样,这里就存方法名。
              isShow: true,
            },
          ],
        },
        {
          path: "/order/refund",
          list: [
            {
              label: "退款编号",
              width: "180",
              align: "center",
              prop: "sn",
              fixed: "left",
              isShow: true,
            },
            ...省略,
            {
              label: "退款原因",
              align: "center",
              width: "160",
              formatter: "formatRefundReason",
              prop: "refundReason",
              isShow: true,
            },
          ],
        },
      ],

2. 侧边栏组件:也就是下面这个展示字段名的组件,里面就是一个checkbbox(全选)和一个el-checkbox-group(参数列表)。

QQ图片20210528141638.png

结构如下:

  <div class="setting">
    <el-checkbox
      v-model="checkAll"
      @change="handleCheckAllChange" //全选,没啥说的,就是把所有的参数里面的isShow都改成true。
      >全选</el-checkbox
    >
    <el-checkbox-group
      v-model="userDefinedList" //绑定的数组
      style="display: flex; flex-direction: column; gap: 6px; margin: 6px 0"
      @change="handleCheckedCitiesChange" //用来存localstrage。
    >
      <el-checkbox
        v-for="item in userDefinedObj.list"
        :label="item.prop"
        :key="item.prop"
        >{{ item.label }}</el-checkbox
      >
    </el-checkbox-group>
  </div>
</template>

3. watch,监听路由,获取当前页面的参数。

    $route(value) {
      this.currentPath = value.path; //路由的path
      this.routeChange();
    },
  },

获取当前页面的表格参数,userDefined就是上面定义的数组,这个数组会存localstrage。

      const data = this.userDefined.find((item) =>item.path == this.currentPath);
      this.userDefinedObj = data?data.list:[];
    },

4.全选和切换选择的时候,都会修改数组中的isShow字段,替换vuex中数据,存到localstrage。

    // 全选事件
    handleCheckAllChange() {
      this.checkChange();
    },
    checkChange() {
      const arr = this.userDefinedList.map((item) => item);
      //userDefined数组第一次是从localstrage中获取,如果没有,就给全部的,字段默认全部显示。
      this.userDefined.forEach((item) => {
        if (item.path == this.currentPath) {
          item.list.forEach((i) => {
            if (arr.includes(i.prop)) {
              i.isShow = true;
            } else {
              i.isShow = false;
            }
          });
        }
      });
      const list = Array.prototype.slice.call(this.userDefined);
      localStorage.setItem("userDefined", JSON.stringify(this.userDefined)); //存本地
      this.saveParamsList(list); //修改vuex中的数据
    },
    // 单个选择事件
    handleCheckedCitiesChange() {
      this.checkChange();
    },

5. 页面中使用,监听vuex中数据变化,切换当前页面列数组。

watch: {
    userDefined: {
      handler() {
        const data = this.userDefined.find((item) =>
          item.path == "/order/refund"
        );
        this.userDefinedObj = data?data.list:[];
      },
      immediate: true,
    },
  },

6. 表格的列,就是循环数组,赋值。

    <el-table-column
          v-for="item in userDefinedObj.filter((item) => item.isShow)" //过滤需要展示的字段。
          :key="item.prop"
          :label="item.label"
          :align="item.align"
          :fixed="item.fixed"
          :width="item.width"
          :formatter="methodsList[item.formatter]" //表格列内容格式化方法,数组中存的是方法名。
          :prop="item.prop"
        ></el-table-column>

7. methodsList是存的格式化列内容的方法,这个方法之所以写在页面中,而不是跟其他的一样放全局数组中,是因为我所有的字段配置都是存localstrage中的,需要JSON.stringify(),但是这个方法没办法保存方法,只能保存方法名,方法还是放在页面组件中。

    methodsList: {
        formatRefundStatus(row, column, cellValue, index) {
          return cellValue == 1 ? "无" : cellValue == 2 ? "有" : "";
        },
        ...省略,
        formatTime(row, column, cellValue, index) {
          let time = new Date(cellValue);
          let y = time.getFullYear();
          let m = time.getMonth() + 1;
          let d = time.getDate();
          let h = time.getHours();
          let mm = time.getMinutes();
          let s = time.getSeconds();
          const value =
            y +
            "-" +
            (m < 10 ? "0" + m : m) +
            "-" +
            (d < 10 ? "0" + d : d) +
            " " +
            (h < 10 ? "0" + h : h) +
            ":" +
            (mm < 10 ? "0" + mm : mm) +
            ":" +
            (s < 10 ? "0" + s : s);
          return cellValue ? value : "暂无";
        },
      },

8. 这个表格字段过滤,只能存一些简单的,固定的内容,但是大家都知道el-table是带有slot的,如果是用slot,就需要改一下。

第一步:和formatter参数一样,增加一个slot字段。

        {
              label: "订单编号",
              align: "center",
              width: "190",
              prop: "orderSn",
              isShow: true,
              hasSlot: true,
              slot: "orderSlot",
            },

第二步:现在有需要用slot和不需要用的,增加一个判断,把scope传到slotList对象中对应的方法,返回需要渲染的html字符串,然后用v-html指令渲染。

    <el-table-column
        v-for="item in userDefinedObj.filter((item) => item.isShow)"
        :key="item.prop"
        :label="item.label"
        :align="item.align"
        :fixed="item.fixed"
        :width="item.width"
        :formatter="methodsList[item.formatter]"
        :prop="item.prop"
      >
        <template slot-scope="scope">
          <div v-if="item.hasSlot" v-html="slotList[item.slot](scope)"></div>
          <div v-else>{{ scope.row[item.prop] }}</div>
        </template>
      </el-table-column>
    </el-table>

slotList对象和methodsList差不多,格式如下:

    slotList: {
        orderSlot: (scope) => {
          return `<div :class="${scope.row.groupPurchaseId} ? 'label_box' : ''">
            <span>${scope.row.orderSn}</span>
          </div>`;
        },
      }