美文网首页
2023.24 element-ui二次封装,实现table-l

2023.24 element-ui二次封装,实现table-l

作者: wo不是黄蓉 | 来源:发表于2023-07-09 08:46 被阅读0次

大家好,我是wo不是黄蓉,今年学习目标从源码共读开始,希望能跟着若川大佬学习源码的思路学到更多的东西。

讲一些比较实用的东西,相信我们经常会用表单和表格实现查询列表功能,通常做法是同一个页面中编写列表,编写表单项,且多个页面相同布局时重复代码多,代码量大。

我们可以通过配置实现表单项和表格列,

实现思路:

  • 通过插槽实现页面布局,然后使用不同的插槽实现表单和表格的自定义。
  • 封装表单项组件,通过接收配置项来生成表单和表格
  • 表单项中有的为输入框组件,有的为下拉组件,可以通过配置项传入参数,然后组件里面使用component :is='xxx'属性来实现表单项里面内容自定义

代码实现:

TableLayout

<template>
  <div class="table_layout_container">
    <div class="table_form">
      <slot name="form"> </slot>
    </div>
    <el-divider></el-divider>
    <div class="table_body_wrap">
      <div class="flex_box table_operation">
        <div class="table_left flex_box">
          <div class="table_header_line"></div>
          <div class="table_header_content">
            <slot name="title">列表</slot>
          </div>
        </div>
        <div class="table_right">
          <slot name="btn"></slot>
        </div>
      </div>
      <div class="table_container">
        <div class="table-content"><slot name="table"></slot></div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'TableLayout',
};
</script>
<style lang="scss" scoped>
@import '@/styles/components/table-layout.scss';
</style>

TableColumns

<template>
  <el-table
    :border="showBorder"
    :data="data"
    :stripe="stripe"
    :height="height"
    tooltip-effect="dark"
    align="center"
    @row-click="rowClick"
    @row-dblclick="rowDblclick"
  >
    <el-table-column
      :label="indexLabel"
      v-if="showIndex"
      type="index"
      width="50"
      align="center"
    >
    </el-table-column>
    <el-table-column
      v-for="(item, index) in columns"
      :key="index"
      :prop="item.prop"
      :label="item.label"
      :width="String(item.width)"
      :min-width="String(item.minWidth)"
      :show-overflow-tooltip="true"
      align="center"
    >
      <template slot-scope="scope">
        <slot v-if="item.showSlot" :name="`${item.prop}`" :scope="scope"></slot>
        <template v-else>{{ scope.row[item.prop] }}</template>
      </template>
    </el-table-column>

    <el-table-column
      :show-overflow-tooltip="true"
      :width="String(operatorWidth)"
      v-if="showOperator"
      label="操作"
      label-width="80px"
      align="center"
    >
      <template slot-scope="scope">
        <slot name="default" :scope="scope"></slot>
      </template>
    </el-table-column>
  </el-table>
</template>
<script>
export default {
  name: 'TableColumns',
  props: {
    data: {
      type: Array,
      default: () => [],
    },
    columns: {
      type: Array,
      default: () => [],
    },
    //是否展示操作栏
    showOperator: {
      type: Boolean,
      default: false,
    },
    //操作栏宽度
    operatorWidth: {
      type: Number,
      default: 100,
    },
    //是否展示边框
    showBorder: {
      type: Boolean,
      default: true,
    },
    //是否展示序列
    showIndex: {
      type: Boolean,
      default: false,
    },
    //自定义序列label
    indexLabel: {
      type: String,
      default: '序号',
    },
    height: {
      type: String,
      default: 'calc(100% - 40px)',
    },
    maxHeight: {
      type: String,
      default: '500',
    },
    stripe: {
      type: Boolean,
      default: true,
    },
  },
  methods: {
    rowClick(row, column, event) {
      this.$emit('rowClick', row, column, event);
    },
    rowDblclick(row, column, event) {
      this.$emit('rowDblclick', row, column, event);
    },
  },
};
</script>

FormItems

<template>
  <el-row>
    <el-col :span="6" v-for="(item, index) in realColumns" :key="index">
      <el-form-item
        :label="item.label + ':'"
        :prop="item.prop"
        :label-width="item.labelWidth + 'px'"
      >
        <slot :name="item.prop" v-if="item.showSlot"></slot>
        <component
          v-else
          size="mini"
          v-model="formData[item.prop]"
          :is="componentType(item.itemType)"
          :clearable="item.clearable || true"
        ></component> </el-form-item
    ></el-col>
    <el-col
      :span="
        realColumns.length % 4 === 1
          ? 18
          : realColumns.length % 4 === 2
          ? 12
          : realColumns.length % 4 === 0
          ? 24
          : 6
      "
    >
      <div class="flex_box">
        <el-button type="primary" @click="onSearch" size="mini">搜索</el-button>
        <el-button @click="onReset" size="mini">重置</el-button>
        <span
          class="no-border"
          @click="changeCollapse"
          v-if="configs.length > 3"
          >{{ isExpand ? '展开' : '收起'
          }}<i
            :class="[
              isExpand ? 'el-icon-arrow-down' : 'el-icon-arrow-up',
              'el-icon--right',
            ]"
          ></i
        ></span>
      </div>
    </el-col>
  </el-row>
</template>
<script>
import { cloneDeep } from 'lodash';
export default {
  name: 'FormItems',
  props: {
    configs: {
      type: Array,
      default: () => [],
    },
    formData: {
      type: Object,
      default: () => {},
    },
    isExpand: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      isExpand: false,
    };
  },
  computed: {
    realColumns() {
      let columns = [];
      if (this.isExpand) {
        columns = cloneDeep(this.configs).filter((item) => {
          return !item.isCollapse;
        });
      } else {
        columns = cloneDeep(this.configs);
      }
      return columns;
    },
  },
  methods: {
    componentType(itemType) {
      if (typeof itemType === 'string') {
        return `${itemType}`;
      }

      return itemType;
    },
    changeCollapse() {
      this.isExpand = !this.isExpand;
    },
    onSearch() {
      this.$emit('onSearch');
    },
    onReset() {
      this.$emit('onReset');
    },
  },
};
</script>
<style lang="scss" scoped>
.flex_box {
  justify-content: flex-end;
}
.el-button--small {
  margin-left: 10px;
}

::v-deep {
  .no-border {
    display: inline-block;
    border: none;
    padding: 9px 15px;
    margin-left: 10px;
    color: #409eff;
    font-size: 12px;
  }
}
</style>

示例

<template>
  <table-layout v-loading="loading">
    <template slot="form">
      <el-form :model="form" label-width="130px" label-position="right">
        <form-items
          :configs="configs"
          :formData="form"
          @onSearch="onSearch"
          @onReset="onReset"
        >
            <template #date> 此处是date的自定义</template>
        </form-items>
      </el-form>
    </template>
    <template slot="btn">
      <el-button type="primary" size="mini" @click="handleAdd(undefined, 'add')"
        >新增 <i class="el-icon-plus"></i
      ></el-button>
    </template>
    <template slot="table">
      <TableColumns
        :data.sync="tableData"
        :columns="columns"
        :showOperator="true"
        :operatorWidth="220"
        height="calc(100% - 40px)"
      >
        <template #default="{ scope }">
          <el-button type="text" @click="edit(scope.row)"
            >编辑</el-button
          ></template
        >
      </TableColumns>
      <el-pagination
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
        :current-page="pageNum"
        :page-sizes="[8]"
        :page-size="8"
        layout="total, sizes, prev, pager, next, jumper"
        :total="total"
      >
      </el-pagination>
    </template>
  </table-layout>
</template>
<script>
import { FormItems, FromData } from './config/form.js';
import { TableColumns } from './config/table.js';
import { page } from '@/mixins/page';
import { cloneDeep } from 'lodash';
export default {
  name: 'DynamicTest',
  mixins: [page],
  data() {
    return {
      form: cloneDeep(FromData),
      configs: cloneDeep(FormItems),
      tableData: [],
      columns: cloneDeep(TableColumns),
      loading: false,
    };
  },
  created() {
    this.onSearch();
  },
  methods: {
    onSearch() {
      this.loading = true;
      this.tableData = [];
      setTimeout(() => {
        this.tableData = [
          {
            date: '2016-05-02',
            name: '王小虎',
            address: '上海市普陀区金沙江路 1518 弄',
          },
          {
            date: '2016-05-04',
            name: '王小虎',
            address: '上海市普陀区金沙江路 1517 弄',
          },
          {
            date: '2016-05-01',
            name: '王小虎',
            address: '上海市普陀区金沙江路 1519 弄',
          },
          {
            date: '2016-05-03',
            name: '王小虎',
            address: '上海市普陀区金沙江路 1516 弄',
          },
        ];
        this.total = this.tableData.length;
        this.loading = false;
      }, 1000);
    },
    onReset() {
      this.form = cloneDeep(FormData);
    },
    edit(row) {
      console.log(row);
    },
  },
};
</script>
<style scoped lang="scss">
::v-deep {
  .el-table th.el-table__cell {
    background-color: #f5f5f5;
  }
}
</style>

form.js

export const FormItems = [
  {
    label: '日期',
    prop: 'date',
    itemType: 'el-input',
    labelWidth: 80,
    showSlot: true,
  },
  {
    label: '姓名',
    prop: 'name',
    itemType: 'el-input',
    labelWidth: 130,
  },
  {
    label: '地址',
    prop: 'address',
    itemType: 'el-input',
    labelWidth: 80,
  },
];

export const FromData = { date: '', name: '', address: '' };

table.js

export const TableColumns = [
  { label: '日期', prop: 'date' },
  { label: '姓名', prop: 'name' },
  { label: '地址', prop: 'address' },
];

效果展示

image.png

element-ui表单和表格的封装,更方便编写带查询的表格页面;支持根据js配置生成表单项和表格列

所有的表单和表格项都是支持的,只是对原有的element-ui提供的功能进行重新封装,多个表单项支持查询条件展开/折叠

Table Layout Slot

name 说明
form 表格查询项自定义
title 表格表头自定义
btn 表格操作区域自定义
table 表格自定义

FormItems Attributes

参数 说明 类型 可选值 默认值
configs 表单项列表 Array []
formData 表单项数据 Array []
isExpand 是否默认展开查询条件,默认不展开 Boolean true/false false

FormItems Methods

方法名 说明 参数
onSearch 点击搜索时回调函数
onReset 点击清空时回调函数

FormItems 和 Table Slot

1.需要在config中添加`showSlot`为`true`
2.配置name为`prop`的slot

TableColumns Attributes

参数 说明 类型 可选值 默认值
data 表格数据项 Array []
columns 表格列 Array []
showOperator 是否展示操作栏 Boolean false
operatorWidth 操作栏宽度 Number 100
showBorder 是否展示边框 Boolean true
showIndex 是否展示序列 Boolean false
indexLabel 自定义序列 label String 序号
height 自定义表格高度 String calc(100% - 40px)
maxHeight 表格最大高度 String 500
stripe 是否使用斑马线 Boolean true

TableColumns Methods

方法名 说明 参数
rowClick 单击行事件 row, column, event
rowDblclick 双击行事件 row, column, event

项目源码

相关文章

网友评论

      本文标题:2023.24 element-ui二次封装,实现table-l

      本文链接:https://www.haomeiwen.com/subject/uffsudtx.html