前言

  • 最近在实际开发中我们遇到一个需求是用户自己控制键值来生成对应表格数据。
  • 换个思路就是我们还是正常查询数据,需要一个开关页面来动态改变表格展示每一列。
  • 我们需要一个开关页面,里面有多选,确定重置取消,确定时把选中数据传递给父组件,动态数据for循环
  • 最好是以封装成组件的形式,可以使代码减少,别的地方也可以用。组件全局注册直接用(主页文章有)

细节

1.可以直接让后端以分页形式把所有需要的字段都返来,最好可以加一个序号。

2.在打开子组件的时候,把默认选中的字段表头重新赋值一次,因为直接在data里面写死的话,子组件侦听器侦听不到,

3.在父组件页面打开的时候可以在month展示一次默认选中数据表格,用户体验较好。

代码如下-可直接复制

父组件

<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>

子组件

<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>





总结:

经过这一趟流程下来相信你也对 Vue -el-table表格动态控制表头动态展示数据(控制每一列展示) 有了初步的深刻印象,但在实际开发中我 们遇到的情况肯定是不一样的,所以我们要理解它的原理,万变不离其宗。加油,打工人!