Vue-el-table table dynamically controls the dynamic display data of the header (controls the display of each column)

foreword

  • Recently, in actual development, we encountered a requirement that the user controls the key value to generate the corresponding table data.

  • Another way of thinking is that we still query data normally, and need a switch page to dynamically change the table to display each column.

  • We need a switch page with multiple choices, confirm to reset and cancel, pass the selected data to the parent component when confirmed, dynamic data for loop

  • It is best to encapsulate it into components, which can reduce the code and can be used in other places. Component global registration is directly used (homepage article has)

detail

1. You can directly let the backend return all the required fields in a paged form, and it is best to add a serial number.

2. When opening the subcomponent, reassign the header of the field selected by default, because if it is written directly in the data, the subcomponent listener will not be able to listen.

3. When the parent component page is opened, the default selected data table can be displayed once in the month, and the user experience is better.

The code is as follows - can be copied directly

parent component

<template>
  <div class="content">
    <!-- 标题 -->
    <div class="title">维保统计报表</div>
    <!-- 搜索 -->
    <el-form class="search" :inline="true" :model="pageInfo" size="mini">
      <el-form-item label="工单类型:">
        <el-input v-model="pageInfo.data" placeholder=""></el-input>
      </el-form-item>
      <el-form-item label="维保小组:">
        <el-input v-model="pageInfo.data" placeholder=""></el-input>
      </el-form-item>
      <el-form-item label="完成情况:">
        <el-input v-model="pageInfo.data" placeholder=""></el-input>
      </el-form-item>
      <el-form-item label="生成时间:">
        <el-input v-model="pageInfo.data" placeholder=""></el-input>
      </el-form-item>
      <el-form-item>
        <el-button @click="onSubmit" icon="el-icon-search" type="primary"
          >查询</el-button
        >
        <el-button @click="showSetting" icon="el-icon-setting" type="primary"
          >配置表单</el-button
        >
      </el-form-item>
    </el-form>
    <!-- 表格数据 -->
    <div class="tables">
      <el-table
        :data="tableData"
        border
        stripe
        size="mini"
        height="100%"
        style="width: 100%"
      >
        <!-- <el-table-column label="序号" width="60" align="center">
          <template slot-scope="scope">
            {
   
   { (pageInfo.pageNo - 1) * pageInfo.pageSize + scope.$index + 1 }}
          </template>
        </el-table-column> -->
        <el-table-column
          v-for="item in showTableColumn"
          :key="item.prop"
          :fixed="item.fixed"
          :align="item.align"
          :prop="item.prop"
          :min-width="item.minWidth"
          :width="item.width"
          :show-overflow-tooltip="item.tooltip"
          :resizable="item.resizable"
          :label="item.label"
        />
      </el-table>
    </div>
    <!-- 配置页面 -->
    <key-setting
      :visible.sync="isSetting"
      :data-arr="AllPropertyArrForManage"
      :check-list="checkProp"
      :default-arr="DefaultPropertyArrForManage"
      @confirm="handleConfirm"
    />
    <!-- 分页查询 -->
    <div class="pagination">
      <el-pagination
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
        :current-page="pageInfo.pageNo"
        :page-sizes="[15, 30, 50, 100]"
        :page-size="pageInfo.pageSize"
        layout="total, sizes, prev, pager, next, jumper"
        :total="pageInfo.total"
      >
      </el-pagination>
    </div>
  </div>
</template>
<script>
export default {
  name: "statics",
  data() {
    return {
      // 分页查询
      pageInfo: {
        // 总条数
        total: 0,
        // 当前页
        pageNo: 1,
        // 每页条数
        pageSize: 15,
        data: "",
      },
      // 选中的表头字段
      showTableColumn: [],
      // 所有数据源
      tableData: [
        {
          serial: "1",
          date: "2016-05-02",
          age: "28",
          gender: "男",
          name: "王虎",
          address: "上海市普陀区金沙江路 1518 弄",
        },
        {
          serial: "2",
          date: "2016-05-04",
          age: "20",
          gender: "男",
          name: "王小虎",
          address: "上海市普陀区金沙江路 1517 弄",
        },
        {
          serial: "3",
          date: "2016-05-01",
          age: "25",
          gender: "男",
          name: "王二虎",
          address: "上海市普陀区金沙江路 1519 弄",
        },
        {
          serial: "4",
          date: "2016-05-03",
          age: "40",
          gender: "男",
          name: "王大虎",
          address: "上海市普陀区金沙江路 1516 弄",
        },
      ],
      // 开关
      isSetting: false,
      // 所有表头字段字段
      AllPropertyArrForManage: [
        {
          prop: "serial",
          label: "序号",
          minWidth: "120",
          align: "center",
          tooltip: true,
          resizable: true,
        },
        {
          prop: "date",
          label: "日期",
          minWidth: "120",
          align: "center",
          tooltip: true,
          resizable: true,
        },
        {
          prop: "age",
          label: "年龄",
          minWidth: "120",
          align: "center",
          tooltip: true,
          resizable: true,
        },
        {
          prop: "gender",
          label: "性别",
          minWidth: "120",
          align: "center",
          tooltip: true,
          resizable: true,
        },
        {
          prop: "name",
          label: "姓名",
          minWidth: "120",
          align: "center",
          tooltip: true,
          resizable: true,
        },
        {
          prop: "address",
          label: "地址",
          minWidth: "120",
          align: "center",
          tooltip: true,
          resizable: true,
        },
      ],
      // 选中字段
      checkProp: [],
      // 默认选中字段
      DefaultPropertyArrForManage: ["name", "age", "serial"],
    };
  },
  created() {},
  mounted() {
    this.dealTableColumn(this.checkProp);
  },
  methods: {
    // 搜索按钮
    onSubmit() {},
    // 分页 左右 点击 输入
    handleSizeChange(val) {
      // console.log(`每页 ${val} 条`);
      this.pageInfo.pageSize = val;
      // this.loadData();
    },
    // 分页多少条点击事件
    handleCurrentChange(val) {
      // console.log(`当前页: ${val}`);
      this.pageInfo.pageNo = val;
      // this.loadData();
    },
    // 点击配置图标
    showSetting() {
      this.isSetting = !this.isSetting;
      // 打开表单
      if (this.isSetting) {
        // 默认选中
        // 重新赋值一次,是因为所有数据和默认选中数据是本来就有的,
        // 重新赋值一次,子组件就可以侦听到值变化了,就可以使子组件多选选中了
        this.checkProp = this.DefaultPropertyArrForManage;
      }
    },
    // 提交确定事件 实际工作中会调接口
    handleConfirm(val) {
      this.checkProp = val;
      this.dealTableColumn(this.checkProp);
    },
    // 重新渲染table表格
    dealTableColumn(arr) {
      console.log("执行了", arr);
      this.showTableColumn = [];
      this.AllPropertyArrForManage.forEach((item) => {
        if (arr.indexOf(item.prop) > -1) {
          this.showTableColumn.push(item);
        }
      });
    },
  },
};
</script>
<style lang="scss" scoped>
.content {
  overflow: hidden;
  background-color: #fff;
  height: 827px;
  margin: 35px 0 25px;
  padding: 5px 10px;
  // 适配谷歌火狐,没有书签栏的上下边距
  @media screen and (min-height: 950px) and (max-height: 990px) {
    margin-top: 50px;
    margin-bottom: 40px;
  }
  // 适配浏览器全屏模式下的上下边距
  @media screen and (min-height: 1070px) {
    margin-top: 100px;
    height: 887px;
    margin-bottom: 60px;
  }
  .title {
    padding-left: 15px;
    font-size: 14px;
    font-weight: 700;
    color: #464c5b;
    line-height: 40px;
    border: solid 1px #e3e8ee;
    background-color: #fff;
    border-radius: 4px;
    &:hover {
      box-shadow: 0 1px 6px rgba(0, 0, 0, 0.2);
      border-color: rgb(233, 231, 231);
    }
  }
  .search {
    padding: 15px 0 0;
  }
  .tables {
    width: 100%;
    height: 595px;
    border-top: 2px solid #2da9fa;
    border-radius: 2px;
    cursor: pointer;
    ::v-deep .el-table__body tr.current-row > td {
      background-color: #fcf0da !important;
    }
    @media screen and (min-height: 1070px) {
      height: 685px;
    }
  }
  .pagination {
    // background-color: skyblue;
    position: fixed;
    bottom: 80px;
    right: 120px;
    // 适配浏览器全屏模式下的上下边距
    @media screen and (min-height: 1070px) {
      bottom: 80px;
    }
  }
}
</style>

Subassembly

<template>
  <div class="wrapper">
    <!-- 控制显示隐藏 -->
    <el-card :style="{ opacity: visible ? '1' : '0' }">
      <div slot="header" style="min-width: 200px">
        <span>字段配置</span>
        <span class="fr close-btn" @click="$emit('update:visible', false)"
          >x</span
        >
      </div>
      <div class="keyconter">
        <el-checkbox
          v-model="checkAll"
          :indeterminate="isIndeterminate"
          @change="selectAll"
          >全选</el-checkbox
        >
        <el-checkbox-group
          v-model="realList"
          class="check-list"
          @change="handleCheckedChange"
        >
          <el-checkbox
            v-for="item in dataArr"
            :key="item.prop"
            :label="item.prop"
            :disabled="item.prop == 'name'"
            >{
   
   { item.label }}</el-checkbox
          >
        </el-checkbox-group>
      </div>
      <div class="footer">
        <el-button
          type="primary"
          size="small"
          :disabled="realList.length < 1"
          @click="confirm"
          >确定</el-button
        >
        <el-button size="small" @click="reset">重置</el-button>
        <el-button size="small" @click="cancel">取消</el-button>
      </div>
    </el-card>
  </div>
</template>
<script>
export default {
  name: "KeySetting",
  props: {
    // 组件开关
    visible: {
      type: Boolean,
      default: false,
    },
    // 表头字段
    dataArr: {
      type: Array,
      default: () => [],
    },
    // 选中字段
    checkList: {
      type: Array,
      default: () => [],
    },
    // 默认选中
    defaultArr: {
      type: Array,
      default: () => [],
    },
  },
  data() {
    return {
      // 全选按钮选中状态
      checkAll: false,
      // 多选框选中值
      realList: [],
      // 判断不确定状态
      isIndeterminate: true,
    };
  },
  watch: {
    checkList(val) {
      console.log("watch", val);
      // 监听选中的字段,等于默认字段,就全选
      this.realList = val;
      if (val.length === this.dataArr.length) {
        // 关闭不确定状态
        this.isIndeterminate = false;
        // 全选
        this.checkAll = true;
      }
    },
  },
  methods: {
    // 全选按钮变化事件
    selectAll(val) {
      // 为true 全选 为false 选中默认值
      this.realList = val
        ? this.dataArr.map((item) => item.prop)
        : this.defaultArr;
      // if (val) {
      //   this.isIndeterminate = false;
      // } else {
      //   this.isIndeterminate = true;
      // }
      this.isIndeterminate = true;
    },
    // el-checkbox选中事件
    // value 是一个数组,里面是多选绑定的值
    handleCheckedChange(value) {
      const checkedCount = value.length;
      // 赋值全选按钮
      // 当选中数组长度等于默认渲染长度就把全选改成勾选状态true
      this.checkAll = checkedCount === this.dataArr.length;
      // 赋值不确定状态
      // 当选中数组长度大于0并且等于默认渲染长度就把不确定状态关闭
      this.isIndeterminate =
        checkedCount > 0 && checkedCount < this.dataArr.length;
    },
    // 点击确定
    confirm() {
      // 把多选框选中值传递给父组件
      this.$emit("confirm", this.realList);
      // 关闭弹框
      this.$emit("update:visible", false);
    },
    // 点击重置
    reset() {
      // 把默认选中绑定给多选选中
      this.realList = [...this.defaultArr];
      // 把不确定状态开启
      this.isIndeterminate = true;
      // 关闭全选按钮
      this.checkAll = false;
    },
    // 点击取消
    cancel() {
      // 把多选框值赋值回原来默认的值
      this.realList = this.checkList;
      // 跟下面这一句是一样效果
      // 把默认选中绑定给多选选中
      // this.realList = [...this.defaultArr];
      // 关闭弹框
      this.$emit("update:visible", false);
    },
  },
};
</script>
<style lang="scss" scoped>
.wrapper {
  //   background-color: red;
  position: fixed;
  width: 300px;
  height: 500px;
  top: 85px;
  right: 30px;
  z-index: 999;
  @media screen and (min-height: 950px) and (max-height: 990px) {
    top: 100px;
  }
  // 适配浏览器全屏模式下的上下边距
  @media screen and (min-height: 1070px) {
    top: 150px;
  }
  .el-card {
    // background-color: skyblue;
    width: 100% !important;
    height: 100%;
    ::v-deep .el-card__body {
      min-height: 87%;
      //   background-color: red;
      position: absolute;
    }
    .footer {
      //   background-color: red;
      position: relative;
      left: 20px;
      bottom: -315px;
    }
  }
}
</style>

Summarize:

After this process, I believe you also have a preliminary deep impression on the Vue-el-table table dynamic control table header dynamic display data (control the display of each column), but the situation we encounter in actual development is definitely different Yes, so we have to understand its principle, which is always the same. Come on, hit the workers!

Please point out any deficiencies, thank you -- Fengguowuhen

Guess you like

Origin blog.csdn.net/weixin_53579656/article/details/130317897