vue 二次封装ElementUI table表格组件

5,582 阅读1分钟

前言

很多业务中有类似表格的操作,尤其是类似后台操作的业务产品等更需要将表格封装起来,以此减轻代码工作量提升开发效率,而且还能统一修改表格样式等等。

这里以ElementUI组件库为前提封装

如图所示:

image.png

项目中大量用到表格时候,这时我们就要考虑把表格进行封装,可以减少代码,提高复用性,维护性好。

原始代码

首先看一下没封装过的代码

<template>
  <div>
      <el-table :data="dataList" border style="width: 100%"> 
        <el-table-column fixed prop="index" label="序号" width="113"> 
          </el-table-column> 
        <el-table-column prop="matterStyleName" label="通道名称" width="120"> 
          </el-table-column>
        <el-table-column prop="province" label="标记类型" width="120">
          </el-table-column>
        <el-table-column prop="userName" label="操作用户" width="120">
          </el-table-column>
        <el-table-column prop="description" label="描述" width="300"> 
          </el-table-column> 
        <el-table-column fixed="right" label="操作" width="100"> 
            <template slot-scope="scope">
                <el-button @click="dialogShow(scope.row)" type="text" size="small">查看录像</el-button>
            </template>
      </el-table>
  </div>
</template>
<script>
import { matter, matterPage, matterExport } from "@api";
import { handleTime } from "@utils/date";

export default {
  components: {
    tableConfig: () => import("@com/jkTableConfig"),
    videoQuertdialog: () =>
      import("@views/Analysis/components/videoQuertdialog.vue"),
  },
  data() {
    return {
      matterTypes: [],
      userId: 0,
      pageSize: 20,
      pageIndex: 1,
      dataList: [],
      row: 0,
    };
  },
  created() {
    this.getMatter();
    this.getMatterPage();
  },

  methods: {
    async getMatter() {
      await matter().then((res) => {
        if (res.status == 200) {
          this.matterTypes = res.message;
        } else {
          this.$message({
            message: `获取标记类型错误,http状态码:${res.status}`,
            type: "warning",
          });
        }
      });
    },
    async getMatterPage() {
      await matterPage(
        this.userId,
        this.formInline.matterType === null ? 0 : this.formInline.matterType,
        {
          PageSize: this.pageSize,
          PageIndex: this.pageIndex,
          StartTime: this.formInline.startTime,
          EndTime: this.formInline.endTime,
        }
      ).then((res) => {
        if (res.status == 200) {
          this.row = res.message.count;
          this.dataList = res.message.data;
        } else {
          this.$message({
            message: `获取标记类型错误,http状态码:${res.status}`,
            type: "warning",
          });
        }
      });
    },
    dialogShow(row) {
      this.$refs.videoQuertdialog.show(row);
    },
  },
};
</script>

表格封装

tab_config.vue

<template>
  <div class="table">
    <el-table
      class="elTable"
      stripe
      height="100%"
      border
      :header-cell-style="tableHeaderColor"
      :cell-style="tableClass"
      :data="tableData"
    >
      <template v-for="item in table_config.thead">
        <el-table-column
          v-if="item.type === 'function'"
          :key="item.prop"
          :label="item.label"
          :width="item.width"
          :prop="item.prop"
          align="center"
        >
          <template slot-scope="scope">
            <span v-html="item.callback && item.callback(scope.row)"></span>
          </template>
        </el-table-column>
        <!-- 操作 -->
        <el-table-column
          v-else-if="item.type === 'operation'"
          :key="item.prop"
          :prop="item.prop"
          :label="item.label"
          :width="item.width"
        >
          <template slot-scope="scope">
            <el-button
              class="btn"
              v-for="items in item.actionButtons"
              :key="items.title"
              :type="items.type"
              @click="item.callback(scope.row, items.title)"
              :icon="items.icon"
              :circle="items.circle"
              ><span v-if="!items.circle">{{ items.title }}</span></el-button
            >
          </template>
        </el-table-column>
        <!-- 普通渲染 -->
        <el-table-column
          v-else
          :key="item.prop"
          :prop="item.prop"
          :label="item.label"
          :width="item.width"
          :min-width="item.minWidth"
          align="center"
        ></el-table-column>
      </template>
    </el-table>
  </div>
</template>
<script>
export default {
  name: "tableConfig",
  props: {
    // 表格数据
    config: {
      type: Object,
      default: () => {},
    },
    tableData: {
      type: Array,
      default: () => {},
    },

  data() {
    return {
      table_config: {
        thead: [],
      },
    };
  },

  methods: {
    //初始化表格数据
    initConfig() {
      for (let key in this.config) {
        if (Object.keys(this.table_config).includes(key)) {
          this.table_config[key] = this.config[key];
        }
      }
    },
    // 斑马线样式
    tableClass({ row, rowIndex }) {
      if (rowIndex % 2 == 1) {
        return "background-color:var(--bgColor1);borderColor:var(--deepBlue);color:#fff;padding:4px";
      } else {
        return "background-color:var(--bgColor2);borderColor:var(--deepBlue);color:#fff;padding:4px";
      }
    },
    // 表头样式
    tableHeaderColor({ row, column, rowIndex, columnIndex }) {
      return "background-color:var(--bgColor3);color:#fff;font-wight:500;font-size:14px;text-align:center;borderColor:var(--deepBlue);padding:4px";
    },
  },
  watch: {
    config: {
      handler(newValue) {
        this.initConfig();
      },
      immediate: true,
    },
  },
};
</script>

可以看到 在表格内 我们分了三种情况

  1. v-if="item.type === 'function'"

    如果接口返回的内容需要我们解析出来并渲染到页面中 比如:0 代表 男 1 代表 女

  2. v-else-if="item.type === 'operation'"

    operation 表示操作栏

  3. v-else

    普通渲染文本

如果你项目中还有别的需求 可以继续添加类型判断

使用

<template>
  <div class="videoQuert">
    <div class="main">
      <tableConfig
        :config="table_config"
        :tableData="dataList"
      />
    </div>

    <videoQuertdialog ref="videoQuertdialog"></videoQuertdialog>
  </div>
</template>
<script>
import { matter, matterPage, matterExport } from "@api";
import { handleTime } from "@utils/date";

export default {
  components: {
    tableConfig: () => import("@com/jkTableConfig"),
    videoQuertdialog: () =>
      import("@views/Analysis/components/videoQuertdialog.vue"),
  },
  data() {
    return {
      // 表格数据
      table_config: {
        thead: [
          { label: "序号", prop: "index", width: "113" },
          { label: "通道名称", prop: "channelName" },
          {
            label: "标记类型",
            prop: "matterStyleName",
          },
          { label: "操作用户", prop: "userName" },
          { label: "描述", prop: "description", minWidth: "250x" },
          {
            label: "操作",
            type: "operation",
            actionButtons: [{ title: "查看录像" }],
            callback: (row, title) => {
              // console.log(row)
              if (title) {
                switch (title) {
                  case "查看录像":
                    return this.dialogShow(row);
                }
              }
            },
          },
        ],
      },

      formInline: {
        startTime: handleTime(
          new Date(new Date().setHours(0, 0, 0, 0)),
          "yyyy-MM-dd HH:mm:ss"
        ),
        endTime: handleTime(new Date(), "yyyy-MM-dd HH:mm:ss"),
        matterType: null,
      },
      matterTypes: [],
      userId: 0,
      pageSize: 20,
      pageIndex: 1,
      dataList: [{}],
      row: 0,
    };
  },
  created() {
    this.getMatterPage();
  },

  methods: {
  
    async getMatterPage() {
      await matterPage(
        this.userId,
        this.formInline.matterType === null ? 0 : this.formInline.matterType,
        {
          PageSize: this.pageSize,
          PageIndex: this.pageIndex,
          StartTime: this.formInline.startTime,
          EndTime: this.formInline.endTime,
        }
      ).then((res) => {
        if (res.status == 200) {
          this.row = res.message.count;
          this.dataList = res.message.data;
        } else {
          this.$message({
            message: `获取标记类型错误,http状态码:${res.status}`,
            type: "warning",
          });
        }
      });
    },
    //打开弹窗
    dialogShow(row) {
      this.$refs.videoQuertdialog.show(row);
    },
  },
};
</script>

直接导入然后把 表格数据 dataList 和 表格配置信息table_config传入

 <tableConfig :config="table_config" :tableData="dataList" />

重点看下配置

 table_config: {
        thead: [
          { label: "序号", prop: "index", width: "113" },
          { label: "通道名称", prop: "channelName" },
          {
            label: "标记类型",
            prop: "matterStyleName",
          },
          { label: "操作用户", prop: "userName" },
          { label: "描述", prop: "description", minWidth: "250x" },
          {
            label: "操作",
            type: "operation",
            actionButtons: [{ title: "查看录像" }],
            callback: (row, title) => {
              // console.log(row)
              if (title) {
                switch (title) {
                  case "查看录像":
                    return this.dialogShow(row);
                }
              }
            },
          },
        ],
      },

这是我们定义的表单数据

其中:thead 包含头部数据

    lable:表示表格头部名称
    
    prop: 表示名称的字段
    
    index: 表示表格的宽度
    
    type: 特殊情况  这里我定义operation 表示这列是操作  actionButtons是个数组 里面title 表示的操作按钮的名称 callback 则是触发的回调
    
callback: (row, title) => { 
    // console.log(row) 
    if (title) { 
        switch (title) { 
            case "查看录像": 
                return this.dialogShow(row); 
                } 
              } 
            },

这里很灵活的可用 switch 判断触发的是那个按钮 然后调用对应的方法

总结:

第一次写文章 主要就是想锻炼下自己 难免写的不好 会慢慢改造 希望大家勿喷!