elementPlus的table二次封装

这篇具有很好参考价值的文章主要介绍了elementPlus的table二次封装。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、简介

公司业务可能需要进行一些组件的封装,基于第三方elementPlus框架,进行符合UI设计原型的组件封装,这篇主要讲解Table表格的封装,目的主要是梳理封装的思路,下面的代码并不是提供完整的源码,因此不包含样式代码。

二、环境准备

webpack+vue3+elementPlus

官方地址:https://element-plus.gitee.io/zh-CN/component/table.html

三、实现步骤

1,成果示例

element plus table 封装,组件,javascript,前端,vue.js,Powered by 金山文档
element plus table 封装,组件,javascript,前端,vue.js,Powered by 金山文档
element plus table 封装,组件,javascript,前端,vue.js,Powered by 金山文档

2,需求分析

(1)表格组件内包含表格数据展示+分页器+搜索input;
(2)表格每列的内容自定义修改,并且支持自定义标签;
(3)搜索和分页器都需要和表格数据联动;
(4)checkbox勾选状态和分页器联动;
(5)搜索栏支持自定义;

3,具体代码

(1)子组件
  • 最终代码示例:
    <el-table
      ref="table"
      :data="tableData"
      :height="height"
      :style="{ fontSize: fontSize, fontFamily: fontFamily }"
      :border="border"
      :stripe="stripe"
      :row-key="
        (row) => {
          return row.id;
        }
      "
      :header-cell-style="{ 'text-align': headerCellStyle }"
      :cell-style="cellStyle"
      @selection-change="handleSelectionChange"
    >
      <!-- checkbox列 -->
      <el-table-column
        v-if="selection"
        type="selection"
        width="56"
        align="center"
        :fixed="fixed"
      >
      </el-table-column>
      <!-- 序号列 -->
      <el-table-column
        v-if="index"
        type="index"
        width="56"
        label="序号"
        :fixed="fixed"
      ></el-table-column>
      <!-- columnData属性列 -->
      <template v-for="item in columnData" :key="item.id">
        <el-table-column
          v-if="item.type === 'link'"
          :label="item.label"
          :prop="item.prop"
          :width="item.width"
          :align="item.align"
          :fixed="item.fixed"
          :sortable="item.sort"
          :formatter="item.formatter"
        >
          <template #default="scope">
            <slot :name="item.prop" v-bind="scope"></slot>
          </template>
        </el-table-column>
        <el-table-column
          v-else-if="item.type === 'tag'"
          :label="item.label"
          :prop="item.prop"
          :width="item.width"
          :align="item.align"
          :fixed="item.fixed"
          :sortable="item.sort"
          :filters="item.filters"
          :filter-method="filterTag"
          :formatter="item.formatter"
        >
          <template #default="scope">
            <slot :name="item.prop" v-bind="scope"></slot>
          </template>
        </el-table-column>
        <el-table-column
          v-else
          :label="item.label"
          :prop="item.prop"
          :width="item.width"
          :align="item.align"
          :fixed="item.fixed"
          :sortable="item.sort"
          :formatter="item.formatter"
        >
        </el-table-column>
      </template>
    </el-table>
  • 实现思路:
1)table的属性和column的属性要分开;
<!--摘自elementPlus表格(基础用法)-->
<template>
  <el-table :data="tableData" style="width: 100%">
    <el-table-column prop="date" label="Date" width="180" />
    <el-table-column prop="name" label="Name" width="180" />
    <el-table-column prop="address" label="Address" />
  </el-table>
</template>

原因:我们来分析一下上面的代码,首先我们需要用组件封装的思想思考。el-table标签上的属性都可以通过父子传值的方式传进组件。但是el-table-column到底有几个我们不确定,那我们很自然的就会想到组件内部需要用到v-for循环,循环的数据也是通过外部传进来。

所以子组件内部发展为:

    <el-table
      ref="table"
      :data="tableData"
    >
      <!-- columnData属性列 -->
      <template v-for="item in columnData" :key="item.id">
        <el-table-column
          :label="item.label" //每列标题内容,参考elemengPlus
          :prop="item.prop" //每列字段名称,参考elemengPlus
          :width="item.width" //每列宽度,参考elemengPlus
          :align="item.align" //每列对齐方式,参考elemengPlus
          :fixed="item.fixed" //首列和标题固定,参考elemengPlus
          :sortable="item.sort" //排序,参考elemengPlus
          :formatter="item.formatter" //支持内容自定义方法,参考elemengPlus
        >
        </el-table-column>
      </template>
    </el-table>
    <script setup>
        import {defineProps} from 'vue'
        defineProps({
            tableData:{
                type:Array
            },
            columnData:{
                type:Array
            }
        })
    </script>

父页面传入的数据发展为:

    const columnData = ref([
      {
        id: 0,
        prop: "contractName",
        // width: "140",
        align: "left",
        label: "常规名称长字段",
      },
      {
        id: 1,
        prop: "contractDate",
        // width: "200",
        align: "left",
        label: "合同日期",
      },
      {
        id: 2,
        prop: "contractAmout",
        // width: "130",
        align: "right",
        label: "合同金额",
        sort: true,
        formatter: (row) => {
          return <div>{row.contractAmout}万</div>;
        },
      },
      {
        id: 3,
        prop: "contractNum",
        // width: "100",
        align: "left",
        label: "合同编号",
      },
      {
        id: 4,
        prop: "operation",
        width: "150",
        align: "left",
        label: "操作",
        type: "slot",
        formatter: (row,column,cellValue,index) => {
          //编辑按钮事件
          const handleEdit = (val) => {
            console.log('row',row);
            console.log('column',column);
            console.log('cellValue',cellValue);
            console.log('index',index);
            // console.log('val',val);
            alert(val.contractName);
          };
          //删除按钮事件
          const handleDelete = (val) => {
            console.log('row',row);
            console.log('column',column);
            console.log('cellValue',cellValue);
            console.log('index',index);
            console.log('row',row);
            // console.log('val',val);
            alert(val.contractName);
          };
          return (
            <div>
              <el-button
                type="primary"
                size="small"
                onClick={() => {
                  handleEdit(row,column,cellValue,index);
                }}
              >
                编辑
              </el-button>
              <el-button
                type="danger"
                size="small"
                onClick={() => {
                  handleDelete(row,column,cellValue,index);
                }}
              >
                删除
              </el-button>
            </div>
          );
        },
      },
    ]);
//表格数据的key键名要和columnData中的prop保持一致
    const tableData = ref([
      {
        "id": "1",
        "contractName": "医院设备1",
        "contractDate": "2023-01-30 14:44:19",
        "contractAmout": "50000",
        "contractNum": "1",
      },
      {
        "id": "2",
        "contractName": "医院设备2",
        "contractDate": "2023-01-29 14:44:19",
        "contractAmout": "30000",
        "contractNum": "2",
      },
      {
        "id": "3",
        "contractName": "医院设备3",
        "contractDate": "2023-01-28 15:44:19",
        "contractAmout": "75000",
        "contractNum": "3",
      },
      {
        "id": "4",
        "contractName": "医院设备4",
        "contractDate": "2023-01-27 15:44:19",
        "contractAmout": "80000",
        "contractNum": "4",
      },
      {
        "id": "5",
        "contractName": "医院设备5",
        "contractDate": "2023-01-26 15:44:19",
        "contractAmout": "80000",
        "contractNum": "5",
      },
      {
        "id": "6",
        "contractName": "医院设备6",
        "contractDate": "2023-01-25 15:44:19",
        "contractAmout": "80000",
        "contractNum": "6",
      },
      {
        "id": "7",
        "contractName": "医院设备7",
        "contractDate": "2023-01-24 15:44:19",
        "contractAmout": "80000",
        "contractNum": "7",
      },
      {
        "id": "8",
        "contractName": "医院设备8",
        "contractDate": "2023-01-23 15:44:19",
        "contractAmout": "80000",
        "contractNum": "8",
      },
      {
        "id": "9",
        "contractName": "医院设备9",
        "contractDate": "2023-01-22 15:44:19",
        "contractAmout": "80000",
        "contractNum": "9",
      },
      {
        "id": "10",
        "contractName": "医院设备10",
        "contractDate": "2023-01-21 15:44:19",
        "contractAmout": "80000",
        "contractNum": "10",
      }
    ]);

注意:表格数据的key键名必须和columnData中的prop保持一致;

2)表格的checkbox列和序号列由外部决定是否需要;

也就是外部传入个布尔值去控制是否渲染这两列即可,所以子组件再前面的基础上再加上:

      <!-- checkbox列 -->
      <el-table-column
        v-if="selection"
        type="selection"
        width="56"
        align="center"
        :fixed="fixed"
      >
      </el-table-column>

      <!-- 序号列 -->
      <el-table-column
        v-if="index"
        type="index"
        width="56"
        label="序号"
        :fixed="fixed"
      ></el-table-column>

    <script setup>
        import {defineProps} from 'vue'
        defineProps({
            tableData:{
                type:Array
            },
            columnData:{
                type:Array
            },
            selection: Boolean,
            index: Boolean,
        })
    </script>

如果需要渲染这两列,父页面使用的时候直接传入相应的布尔值即可,如下示例:

    <flex-table
      ref="flexTable"
      :columnData="columnData"
      :tableData="tableData"
      selection
      index
    >
3)插槽支持更多框架内容自定义;

由于formatter的方法内部是react写法,不支持template标签。如果自定义的内容包含el-tag标签或其他可扩展内容时,可以通过插槽实现;

子组件内部就变成了:

      <!-- columnData属性列 -->
      <template v-for="item in columnData" :key="item.id">
        <!-- 扩展列 -->
        <el-table-column
          v-if="item.type === 'link'"
          :label="item.label"
          :prop="item.prop"
          :width="item.width"
          :align="item.align"
          :fixed="item.fixed"
          :sortable="item.sort"
          :formatter="item.formatter"
        >
          <template #default="scope">
            <slot :name="item.prop" v-bind="scope"></slot>
          </template>
        </el-table-column>
        <!-- 标签列 -->
        <el-table-column
          v-else-if="item.type === 'tag'"
          :label="item.label"
          :prop="item.prop"
          :width="item.width"
          :align="item.align"
          :fixed="item.fixed"
          :sortable="item.sort"
          :filters="item.filters"
          :filter-method="filterTag"
          :formatter="item.formatter"
        >
          <template #default="scope">
            <slot :name="item.prop" v-bind="scope"></slot>
          </template>
        </el-table-column>
        <!-- 其他正常列 -->
        <el-table-column
          v-else
          :label="item.label"
          :prop="item.prop"
          :width="item.width"
          :align="item.align"
          :fixed="item.fixed"
          :sortable="item.sort"
          :formatter="item.formatter"
        >
        </el-table-column>
      </template>

父页面使用的时候就可以通过插槽的名称来实现内容的自定义:

tag标签插槽:

<template #state="{ row }">
  <el-tag v-if="row.state === '进行中'" type="primary">{{
    row.state
    }}</el-tag>
  <el-tag v-if="row.state === '已完成'" type="success">{{
    row.state
    }}</el-tag>
  <el-tag v-if="row.state === '已终止'" type="danger">{{
    row.state
    }}</el-tag>
  <el-tag v-if="row.state === '已中止'" type="warning">{{
    row.state
    }}</el-tag>
  <el-tag v-if="row.state === '已取消'" type="info">{{
    row.state
    }}</el-tag>
</template>

link扩展链接插槽:

<template #link="{ row }">
    <ul class="linkMenu">
        <li>
          <el-link type="primary" v-if="row.link === 1">催填</el-link>
          <el-link type="primary" v-if="row.link === 2">汇总</el-link>
          <el-link type="primary" v-if="row.link === 3">重新汇总</el-link>
          <el-link type="primary" v-if="row.link === 4">重新确认</el-link>
          <el-link type="primary" v-if="row.link === 5">调整</el-link>
        </li>
    </ul>
</template>
4)配置搜索表单
<!--labelWidth和labelPosition是el-form的属性,参考elementPlus-->
<el-form :label-width="labelWidth" :label-position="labelPosition">
    <slot name="search"></slot>
</el-form>

在el-table标签上方加上如上代码,使用插槽支持自定义;

在父页面使用的时候:

      <!-- 搜索插槽 -->
      <template v-slot:search>
        <div class="ipt-btn">
          <!-- 输入框 -->
          <el-row gutter="0">
            <!-- 第一行 -->
            <el-col :span="8">
              <el-form-item label="标题标题">
                <el-input
                  placeholder="请输入"
                  v-model="form.value1"
                  @keyup.enter="handleFilter(form)"
                />
              </el-form-item>
            </el-col>
            <el-col :span="8">
              <el-form-item label="标题标题">
                <el-input
                  placeholder="请输入"
                  v-model="form.value2"
                  @keyup.enter="handleFilter(form)"
                />
              </el-form-item>
            </el-col>
            <el-col :span="8">
              <el-form-item label="标题标题">
                <el-input
                  placeholder="请输入"
                  v-model="form.value3"
                  @keyup.enter="handleFilter(form)"
                />
              </el-form-item>
            </el-col>
            <!-- 第二行 -->
            <el-col :span="8">
              <el-form-item label="标题标题" v-show="isShow">
                <el-select v-model="form.value5" @change="handleFilter(form)">
                  <el-option label="选项一" value="选项一">选项一</el-option>
                  <el-option label="选项二" value="选项二">选项二</el-option>
                </el-select>
              </el-form-item>
            </el-col>
            <el-col :span="8">
              <el-form-item label="标题标题" v-show="isShow">
                <el-date-picker
                  value-format="YYYY-MM-DD"
                  placeholder="请选择"
                  v-model="form.value6"
                  @change="handleFilter(form)"
                ></el-date-picker>
              </el-form-item>
            </el-col>
            <el-col :span="8">
              <el-form-item label="标题标题" v-show="isShow">
                <el-date-picker
                  type="datetime"
                  placeholder="请选择"
                  v-model="form.value7"
                  value-format="YYYY-MM-DD HH:mm:ss"
                  @change="handleFilter(form)"
                ></el-date-picker>
              </el-form-item>
            </el-col>
          </el-row>
          <!-- 按钮 -->
          <div class="btn">
            <el-form-item class="btns">
              <el-button
                class="arrow"
                :icon="isShow ? ArrowUp : ArrowDown"
                @click="isShow = !isShow"
              ></el-button>
              <el-button
                class="reset"
                @click="resetForm"
                >重置</el-button
              >
              <el-button
                class="confirm"
                type="primary"
                @click="onSubmit"
                >确定</el-button
              >
            </el-form-item>
          </div>
        </div>
      </template>
    <script setup>
    import {ref, reactive} from 'vue'
    const isShow = ref(false);
    const form = reactive({
      value1: "张三",
      value2: "10",
      value3: "",
      value4: "",
      value5: "",
      value6: "",
      value7: "",
    });
    </script>

展开效果图:

element plus table 封装,组件,javascript,前端,vue.js,Powered by 金山文档

隐藏效果图:

element plus table 封装,组件,javascript,前端,vue.js,Powered by 金山文档
5)配置分页器

效果图:

element plus table 封装,组件,javascript,前端,vue.js,Powered by 金山文档

直接运用el-pagination,html代码示例:

    <div class="bottom_box">
    <!-- 左侧统计checkbox选中状态 -->
      <ul class="flex-ul">
        <li>
          已选择<span style="color: #3480fb" v-if="checkNumber > 0">{{
            checkNumber
          }}</span
          >项
        </li>
        <li>|</li>
        <li class="cancelCheckBox" @click="toggleSelection">
          <span style="color: #3480fb">取消</span>
        </li>
      </ul>
    <!-- 右侧分页器组件 -->
      <el-pagination
        :small="small" //是否启用小型分页器,字号12px
        :background="background" //页码选中是否有背景色
        layout="total, prev, pager, next, sizes, jumper" //分页器各组件
        :total="total" //总条数
        :pager-count="4" //设置最大按钮数
        :page-size="pageSize" //每页显示条数
        :page-sizes="pageSizes" //每页显示个数选择器的选项设置
        @size-change="sizeChange" //page-size 改变时触发
        @current-change="handleCurrentChange" //页码发生变化触发事件
      />
    </div>

参考elementPlus的方法,结合vue3的写法,js代码示例:

    //checkbox点击事件
    const instance = getCurrentInstance();
    const table = ref(null);
    const multipleSelection = ref([]);
    const checkNumber = ref(null);
    //取消勾选事件
    const toggleSelection = () => {
      var ultipleTabInstance = toRefs(instance.refs.table);
      ultipleTabInstance.clearSelection.value();
    };
    //勾选checkbox事件
    const handleSelectionChange = (val) => {
      console.log("val", val);
      multipleSelection.value = val;
      checkNumber.value = multipleSelection.value.length;
    };
(2)父组件
  • 最终代码示例:
    <flex-table
      ref="flexTable"
      size="large"
      disabled
      background
      prevIcon="ArrowLeft"
      nextIcon="ArrowRight"
      :url="apiUrl.tableList2"
      :requestData="request_data"
      :columnData="columnData"
      :pageSizes="pageSizes"
      fontSize="14px"
      fontFamily="PingFangSC-Regular"
      labelWidth="110"
      selection
      border
      fixed
    >
      <!-- 链接插槽 -->
      <template #link="{ row }">
        <ul class="linkMenu">
          <li>
            <el-link type="primary" v-if="row.link === 1">催填</el-link>
            <el-link type="primary" v-if="row.link === 2">汇总</el-link>
            <el-link type="primary" v-if="row.link === 3">重新汇总</el-link>
            <el-link type="primary" v-if="row.link === 4">重新确认</el-link>
            <el-link type="primary" v-if="row.link === 5">调整</el-link>
          </li>
          <li>|</li>
          <li v-if="row.link === 1">
            <el-dropdown>
              <span class="el-dropdown-link">
                二级配置
                <el-icon class="el-icon--right">
                  <arrow-down />
                </el-icon>
              </span>
              <template #dropdown>
                <el-dropdown-menu>
                  <el-dropdown-item>更多菜单一</el-dropdown-item>
                  <el-dropdown-item>更多菜单二</el-dropdown-item>
                  <el-dropdown-item>更多菜单三</el-dropdown-item>
                  <el-dropdown-item>更多菜单四</el-dropdown-item>
                </el-dropdown-menu>
              </template>
            </el-dropdown>
          </li>
          <li v-if="row.link === 2">
            <el-dropdown>
              <span class="el-dropdown-link">
                上会结束
                <el-icon class="el-icon--right">
                  <arrow-down />
                </el-icon>
              </span>
              <template #dropdown>
                <el-dropdown-menu>
                  <el-dropdown-item>更多菜单一</el-dropdown-item>
                  <el-dropdown-item>更多菜单二</el-dropdown-item>
                  <el-dropdown-item>更多菜单三</el-dropdown-item>
                  <el-dropdown-item>更多菜单四</el-dropdown-item>
                </el-dropdown-menu>
              </template>
            </el-dropdown>
          </li>
          <li v-if="row.link === 3">
            <el-dropdown>
              <span class="el-dropdown-link">
                二级配置
                <el-icon class="el-icon--right">
                  <arrow-down />
                </el-icon>
              </span>
              <template #dropdown>
                <el-dropdown-menu>
                  <el-dropdown-item>更多菜单一</el-dropdown-item>
                  <el-dropdown-item>更多菜单二</el-dropdown-item>
                  <el-dropdown-item>更多菜单三</el-dropdown-item>
                  <el-dropdown-item>更多菜单四</el-dropdown-item>
                </el-dropdown-menu>
              </template>
            </el-dropdown>
          </li>
          <li v-if="row.link === 4">
            <el-dropdown>
              <span class="el-dropdown-link">
                上会结束
                <el-icon class="el-icon--right">
                  <arrow-down />
                </el-icon>
              </span>
              <template #dropdown>
                <el-dropdown-menu>
                  <el-dropdown-item>更多菜单一</el-dropdown-item>
                  <el-dropdown-item>更多菜单二</el-dropdown-item>
                  <el-dropdown-item>更多菜单三</el-dropdown-item>
                  <el-dropdown-item>更多菜单四</el-dropdown-item>
                </el-dropdown-menu>
              </template>
            </el-dropdown>
          </li>
          <li v-if="row.link === 5">
            <el-dropdown>
              <span class="el-dropdown-link">
                二级配置
                <el-icon class="el-icon--right">
                  <arrow-down />
                </el-icon>
              </span>
              <template #dropdown>
                <el-dropdown-menu>
                  <el-dropdown-item>更多菜单一</el-dropdown-item>
                  <el-dropdown-item>更多菜单二</el-dropdown-item>
                  <el-dropdown-item>更多菜单三</el-dropdown-item>
                  <el-dropdown-item>更多菜单四</el-dropdown-item>
                </el-dropdown-menu>
              </template>
            </el-dropdown>
          </li>
        </ul>
      </template>
      <!-- 标签插槽 -->
      <template #state="{ row }">
        <el-tag v-if="row.state === '进行中'">{{ row.state }}</el-tag>
        <el-tag v-if="row.state === '已完成'" type="success">{{
          row.state
        }}</el-tag>
        <el-tag v-if="row.state === '已终止'" type="danger">{{
          row.state
        }}</el-tag>
        <el-tag v-if="row.state === '已中止'" type="warning">{{
          row.state
        }}</el-tag>
        <el-tag v-if="row.state === '已取消'" type="info">{{
          row.state
        }}</el-tag>
      </template>
      <!-- 搜索插槽 -->
      <template v-slot:search>
        <div class="ipt-btn">
          <!-- 输入框 -->
          <el-row gutter="0">
            <!-- 第一行 -->
            <el-col :span="8">
              <el-form-item label="标题标题">
                <el-input
                  placeholder="请输入"
                  v-model="form.value1"
                  @keyup.enter="handleFilter(form)"
                />
              </el-form-item>
            </el-col>
            <el-col :span="8">
              <el-form-item label="标题标题">
                <el-input
                  placeholder="请输入"
                  v-model="form.value2"
                  @keyup.enter="handleFilter(form)"
                />
              </el-form-item>
            </el-col>
            <el-col :span="8">
              <el-form-item label="标题标题">
                <el-input
                  placeholder="请输入"
                  v-model="form.value3"
                  @keyup.enter="handleFilter(form)"
                />
              </el-form-item>
            </el-col>
            <!-- <el-col :span="6">
              <el-form-item label="标题标题">
                <el-input
                  v-model="form.value4"
                  placeholder="请输入"
                  @keyup.enter="handleFilter(form)"
                ></el-input>
              </el-form-item>
            </el-col> -->
            <!-- 第二行 -->
            <el-col :span="8">
              <el-form-item label="标题标题" v-show="isShow">
                <el-select v-model="form.value5" @change="handleFilter(form)">
                  <el-option label="选项一" value="选项一">选项一</el-option>
                  <el-option label="选项二" value="选项二">选项二</el-option>
                </el-select>
              </el-form-item>
            </el-col>
            <el-col :span="8">
              <el-form-item label="标题标题" v-show="isShow">
                <el-date-picker
                  value-format="YYYY-MM-DD"
                  placeholder="请选择"
                  v-model="form.value6"
                  @change="handleFilter(form)"
                ></el-date-picker>
              </el-form-item>
            </el-col>
            <el-col :span="8">
              <el-form-item label="标题标题" v-show="isShow">
                <el-date-picker
                  type="datetime"
                  placeholder="请选择"
                  v-model="form.value7"
                  value-format="YYYY-MM-DD HH:mm:ss"
                  @change="handleFilter(form)"
                ></el-date-picker>
              </el-form-item>
            </el-col>
          </el-row>
          <!-- 按钮 -->
          <div class="btn">
            <el-form-item class="btns">
              <el-button
                style="
                  width: 30px;
                  height: 34px;
                  background: #eef1f5;
                  borderradius: 4px;
                "
                class="arrow"
                :icon="isShow ? ArrowUp : ArrowDown"
                @click="isShow = !isShow"
              ></el-button>
              <el-button
                class="reset"
                @click="resetForm"
                style="
                  width: 50px;
                  height: 34px;
                  border: 1px solid rgba(0, 0, 0, 0.2);
                  border-radius: 4px;
                "
                >重置</el-button
              >
              <el-button
                class="confirm"
                type="primary"
                @click="onSubmit"
                style="
                  width: 50px;
                  height: 34px;
                  background: #3480FB;
                  border-radius: 4px;
                "
                >确定</el-button
              >
            </el-form-item>
          </div>
        </div>
      </template>
    </flex-table>
  </div>

四、真实业务对接

如果业务要求直接传入url就可以实现数据渲染的话,就需要在组件内部去进行数据请求,下面主要进行axios请求mock数据模拟,先测试可行性,再根据真实数据对接即可。

1,实现表格数据成功渲染

(1),步骤一:下载依赖

yarn add mockjs / npm i mockjs

yarn add axios/ npm i axios

(2),步骤二:mock数据模拟

在scr文件夹下新建mock文件夹,新建index.js文件,和mockData文件夹;

element plus table 封装,组件,javascript,前端,vue.js,Powered by 金山文档

在mockData文件里新建table.json文件,写上tableData的数据

{
      "totalElements":10, //总条数
      "page":1, //当前页码
      "rows":5, //每行显示条数
      "content":[
      {
        "id": "1",
        "contractName": "医院设备1",
        "contractDate": "2023-01-30 14:44:19",
        "contractAmout": "50000",
        "contractNum": "1",
      },
      {
        "id": "2",
        "contractName": "医院设备2",
        "contractDate": "2023-01-29 14:44:19",
        "contractAmout": "30000",
        "contractNum": "2",
      },
      {
        "id": "3",
        "contractName": "医院设备3",
        "contractDate": "2023-01-28 15:44:19",
        "contractAmout": "75000",
        "contractNum": "3",
      },
      {
        "id": "4",
        "contractName": "医院设备4",
        "contractDate": "2023-01-27 15:44:19",
        "contractAmout": "80000",
        "contractNum": "4",
      },
      {
        "id": "5",
        "contractName": "医院设备5",
        "contractDate": "2023-01-26 15:44:19",
        "contractAmout": "80000",
        "contractNum": "5",
      },
      {
        "id": "6",
        "contractName": "医院设备6",
        "contractDate": "2023-01-25 15:44:19",
        "contractAmout": "80000",
        "contractNum": "6",
      },
      {
        "id": "7",
        "contractName": "医院设备7",
        "contractDate": "2023-01-24 15:44:19",
        "contractAmout": "80000",
        "contractNum": "7",
      },
      {
        "id": "8",
        "contractName": "医院设备8",
        "contractDate": "2023-01-23 15:44:19",
        "contractAmout": "80000",
        "contractNum": "8",
      },
      {
        "id": "9",
        "contractName": "医院设备9",
        "contractDate": "2023-01-22 15:44:19",
        "contractAmout": "80000",
        "contractNum": "9",
      },
      {
        "id": "10",
        "contractName": "医院设备10",
        "contractDate": "2023-01-21 15:44:19",
        "contractAmout": "80000",
        "contractNum": "10",
      }
      ]
    }
  ]
}

另外在index.js文件中配置mock数据请求地址:

import Mock from 'mockjs';
import tableData from './mockData/tableData.json';
Mock.mock("/getData",(config)=>{
  let params = Json.parse(config.body) //这里是请求的参数
  return {
        success:true,
        data:tableData
    }
})

最后一定要记得在main.js文件中引入mock文件夹下的index.js文件

import './mock/index'

(3),步骤三:封装axios请求,新建api文件夹
element plus table 封装,组件,javascript,前端,vue.js,Powered by 金山文档
import axios from 'axios';
import {ElMessage} from 'element-plus';
//请求表格数据
const getTableData = (url, data)=>{
  console.log('post请求参数',data);
  return axios({
    method:'post',
    url:url,
    data:data
  }).then(
    res => {
      return res.data
    },
    error => {
      ElMessage({
        type:'error',
        message:error.message,
        showClose: true
      })
    }
  )
}
export default getTableData
(4),步骤四:组件中引入方法请求数据

组件代码:

import getTableData from "../api/table";
props: {
    //外部传入url,但也需要给个默认值
    url: {
      type: String,
      require: true,
      default: "/getData",
    },
}
//get请求数据方法
const getTableList = (url, options) => {
//判断url不存在不继续进行请求
  if (!url) {
      console.log("请求地址不存在!");
      return false;
   }
   getTableData(url, options).then((res) => {
      console.log("res", res);      
      const { data } = res;
      //处理请求数据内容渲染表格
      tableData.value = data.content;
    });
};
onMounted(() => {
  getTableList(props.url, props.requestData);
});

使用父页面:

<flex-table
    url="/getData"
    :columnData="columnData"
></flex-table>

阶段总结:基本上表格的数据已经可以渲染出来了,至于请求request拦截器,需要和后端配合去完善。这里主要是前端先负责渲染出数据和调整效果样式等。

2,实现分页器和搜索框请求参数

(1)步骤一:tableData.json数据中添加分页器参数
"totalElements":10, //总条数
"page":1, //当前页码
"rows":5, //每行显示条数
(2)步骤二:组件内处理请求参数
<el-pagination
        :small="small" //是否启用小型分页器,字号12px
        :background="background" //页码选中是否有背景色
        layout="total, prev, pager, next, sizes, jumper" //分页器各组件
        :total="total" //总条数
        :pager-count="4" //设置最大按钮数
        :page-size="pageSize" //每页显示条数
        :page-sizes="pageSizes" //每页显示个数选择器的选项设置
        @size-change="sizeChange" //page-size 改变时触发
        @current-change="handleCurrentChange" //页码发生变化触发事件
      />
const total = ref(10); //总条数,可以给个默认值
const pageSize = ref(10); //每页条数,可以给个默认值
const currentPage = ref(1); //当前页码,可以给个默认值

//get请求数据方法
const getTableList = (url, options) => {
//判断url不存在不继续进行请求
  if (!url) {
      console.log("请求地址不存在!");
      return false;
   }
   getTableData(url, options).then((res) => {
      console.log("res", res);      
      const { data } = res;
      //处理请求数据内容渲染表格
      tableData.value = data.content;
      //处理请求数据总条数 ---后端给的
      total.value = data.totalElements;
      //处理请求每页显示条数 ---后端给的
      pageSize.value = data.rows;
      //处理请求当前显示页码 ---后端给的
      currentPage.value = data.page;
    });
};
(3)步骤三:处理页码变化时,传入相应的值给参数进行请求数据

父组件传入请求分页器参数

<flex-table
    url="/getData"
    :columnData="columnData"
    :requestData="request_data"
></flex-table>
<script>
    const request_data = reactive({
      page: 1, //当前页码
      rows: 10, //每页显示条数
      searchVal: {}, //搜索框输入的值
    });
</script>
    import {
      ref,
      computed,
      onMounted,
      getCurrentInstance,
      toRefs,
      defineExpose,
      defineEmits,
    } from "vue";
    
    props: {
        //分页器请求参数
        requestData: {
          type: Object,
          default: () => ({
            page: 1, //当前页数
            rows: 10, //显示条数
            searchVal: {}, //搜索框的值
          }),
        },
    }

    //处理props值可以重新赋值
    const emits = defineEmits();    
    const pageParams = computed({
       get: () => {
          return props.requestData;
       },
       set: (val) => {
          emits("update:requestData", val);
       },
    });

    //当前页码变化事件
    const handleCurrentChange = (val) => {
      //把当前页码赋值给请求参数
      pageParams.value.page = val;
      //请求数据
      getTableList(props.url, pageParams.value);
    };
    //每页显示条数变化事件
    const sizeChange = (val) => {
      //把变化的每页显示条数赋值给请求参数
      pageParams.value.rows = val;
      //请求数据
      getTableList(props.url, pageParams.value)
    };
    //上一页点击事件
    const handlePreClick = (val) => {
      console.log(`handlePreClick,点击了上一页,当前第${val}页`);
    };
    //下一页点击事件
    const handleNextClick = (val) => {
      console.log(`handleNextClick,点击了下一页,当前第${val}页`);
    };

注意:这里为什么需要用外部传入的requestData?

因为外部使用的时候需要用到searchVal,也就是搜索栏输入框的值;也有可能从刚开始请求表格初始数据的时候,需要传入特定页码和特定关键词的数据,所以暴露在外面可以提高组件的灵活性。

(4)步骤四:验证是否成功传入参数
import Mock from 'mockjs';
import tableData from './mockData/tableData.json';
Mock.mock("/getData",(config)=>{
  let params = Json.parse(config.body) 
  console.log(params) //这里打印验证是否更新参数
  return {
        success:true,
        data:tableData
    }
})
(5)步骤五:mock手动模拟切换数据的效果

目前分页器和搜索框的值就暴露到了请求数据的参数中。但是在mock中想要实现有切换数据的效果,我们需要根据返回的参数自己模拟mock返回的数据。

import tableData1 from './mockData/tableData1.json'
import tableData2 from './mockData/tableData2.json'

Mock.mock("/getData",(config)=>{
  let params = JSON.parse(config.body)
  //如果当前页码 = 2,返回第二页数据
  if(params.page == 2){
    return {
      success: true,
      data: tableData1,
    }
  }else if(params.page == 1){
    //如果当前页码 = 1,返回第一页数据
    return {
      success: true,
      data: tableData2,
    };
  }
})

这样简单的数据切换的效果就实现了,方便去调试传给后端的参数;

3,实现外部调用内部reload方法

因为搜索表单内容是插槽,外部自己写搜索表单的样式和布局,所以包括表单提交事件也是在组件外去操作的,那这个时候就需求去调用内部的请求去重新请求数据。vue3的话可以通过ref来实现。

(1)步骤一:父组件需要给子组件绑定ref
<flex-table ref="flexTable"></flex-table>
    const flexTable = ref(null)    
    //搜索表单v-model的值
    const form = reactive({
      value1: "张三",
      value2: "10",
      value3: "",
      value4: "",
      value5: "",
      value6: "",
      value7: "",
    });    
    //重置按钮
    const resetForm = () => {
      Object.keys(form).forEach((key) => (form[key] = ""));
      flexTable.value.reload(form);
    };
    //提交按钮
    const onSubmit = () => {
      flexTable.value.reload(form);
    };
    //输入框enter事件
    const handleFilter = (val) => {
      flexTable.value.reload(val);
    };
(2)步骤二:子组件处理reload方法
    //reload请求方法
    const reload = (val) => {
      pageParams.value.searchVal = val;
      getTableList(props.url, pageParams.value);
    };
(3)步骤三:子组件暴露出去reload方法
defineExpose({
  reload,
});

五,注意说明

1,关于代码写法

因为之前开发组件的时候需要用到name,所以用的写法是vue3的,没有用到setup语法糖。后面在完善的时候发现可以实现setup语法,也可以保留name。亲测有效。

<sctipt>
export default{
    name:"组件名"
}
</script>
<sctipt setup>
    //正常业务代码
</script>

2,关于组件内其他属性

这里主要讲解了一些重要的常用的属性,至于其他控制样式的属性可以参考elementPlus的组件属性表。

3,关于组件组件开发框架搭建

这个之前也是慢慢研究的,但是还没有整理,整理之后再单独更新吧。

4,关于对接真实接口

上面主要展示的是mock数据的对接模拟,至于真实数据需要对接自己的后端给的字段或者要求等;情况不一。但是大概的思路都可以参考的,大家可以根据自己的真实接口去灵活应用的。

5,关于组件需求

不同业务或许有不同的组件封装需求,以上主要是提供一些需求的一种解决方案,大家可以灵活参考。文章来源地址https://www.toymoban.com/news/detail-600158.html

到了这里,关于elementPlus的table二次封装的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Element UI 表格 el-table 二次封装

    Tips: 文章末尾有完整封装代码 一、继承 element 表格属性 需要将element提供的表格属性使用props传入组件中 二、配置 element 表格的表头 使用 props 传入的表头数据遍历得到表格的表头。 有些列的数据需要自定义内容,例如:操作列、不同样式的数据展示等。 方式一 需要自定义

    2023年04月08日
    浏览(46)
  • element ui el-table进行二次封装

    在做项目的时候特别是后台管理的时候table难免用的多,所有根据vue框架对table进行二次封装 好处那就是可以省很多代码,而且用起来也方便。非常的奈斯 封装的内容 组件内的按钮以及复选框分页都是通过变量来控制。 组件内部也是写了方法通过子传父使父组件更好的去使

    2024年02月12日
    浏览(46)
  • 如何二次封装一个el-table组件并二次复用

    *注:示例使用的是vue3和element+进行二次封装的 表格数据操作按钮区域 表格信息提示区域 表格主体内容展示区域 表格分页区域 表单搜索没有封装在这里是为了降低代码的耦合性(有兴趣的可以查看我之前写的搜索框封装如何封装一个后管的输入框按钮组件基础版(可多次复用

    2024年02月16日
    浏览(47)
  • vue3 element-plus el-form的二次封装

    form表单的二次封装 vue3 element-plus el-form的二次封装 属性名 类型 默认值 说明 data Array [] 页面展示数据内容 onChange Function false 表单事件 bindProps Object {} 表单属性 formRef Object {} 表单ref ruleForm Object {} 数据

    2024年02月13日
    浏览(68)
  • vue3 基于element plus对el-pagination进行二次封装

    在vue3项目中,如果每个列表页都敲一遍分页方法,显然是不合理的,那么,下面我将基于element plus对el-pagination进行二次封装,使用vue3语法糖格式,废话不多说,开干。

    2024年02月12日
    浏览(46)
  • element ui 表格组件与分页组件的二次封装

    目录 效果图  组件封装  parseTime函数 debounce 函数 render通用渲染模版 页面使用 【扩展】vue 函数式组件 函数式组件特点: 函数式组件的优点: 【扩展】vue中的render函数 一、初步认识render函数 二、为什么使用render函数 三、render函数的解析 【扩展】添加操作栏显示权限 结构

    2024年02月08日
    浏览(46)
  • vue+element plus 使用table组件,清空用户的选择项

    使用官方方法  clearSelection ,  tableRef.value.clearSelection() 清除table组件 用户的选择项。

    2024年02月07日
    浏览(49)
  • vue3封装element-ui-plus组件

    最近看视频学习封装公共组件,将学习的内容记录以下,方便以后cv。 下面跟未来的自己说:         先说思路再放代码嗷,我怕你以后忘了。要cv直接往最后拉。 思路:         其实主要是通过slot去接收父组件传递过来的模板。父组件引用了组件件,往里面传了个表单,

    2024年02月09日
    浏览(67)
  • Vue3 + Element Plus 封装公共表格组件(带源码)

    由于项目中有很多菜单都是列表数据的展示,为避免太多重复代码,故将 Element Plus 的 Table 表格进行封装,实现通过配置展示列表数据 支持自动获取表格数据 支持数据列配置及插槽 支持操作列配置及插槽 支持多选框配置 支持表尾配置及插槽 支持分页显示 3.1 复制基本表格

    2024年02月08日
    浏览(86)
  • vue3 ts element plus form表单二次封装详细步骤 (附参数、类型详细介绍及简单使用示例)

    上篇table 表格封装 讲到项目中经常会用到 table 表格,所以做了封装。当然,form 表单使用的频率依然很高,所以和封装 table 表格的思路相似,对 form 表单也做了一个二次封装的组件。 查看国内预览站 查看国外预览站 1. EasyForm 表单组件封装 src/components/EasyForm/index.vue Form 表单

    2024年02月07日
    浏览(60)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包