当前位置:   article > 正文

elementPlus的table二次封装_elementplus table二次封装

elementplus table二次封装

一、简介

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

二、环境准备

webpack+vue3+elementPlus

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

三、实现步骤

1,成果示例

2,需求分析

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

3,具体代码

(1)子组件
  • 最终代码示例:
  1.     <el-table
  2. ref="table"
  3. :data="tableData"
  4. :height="height"
  5. :style="{ fontSize: fontSize, fontFamily: fontFamily }"
  6. :border="border"
  7. :stripe="stripe"
  8. :row-key="
  9. (row) => {
  10. return row.id;
  11. }
  12. "
  13. :header-cell-style="{ 'text-align': headerCellStyle }"
  14. :cell-style="cellStyle"
  15. @selection-change="handleSelectionChange"
  16. >
  17. <!-- checkbox列 -->
  18. <el-table-column
  19. v-if="selection"
  20. type="selection"
  21. width="56"
  22. align="center"
  23. :fixed="fixed"
  24. >
  25. </el-table-column>
  26. <!-- 序号列 -->
  27. <el-table-column
  28. v-if="index"
  29. type="index"
  30. width="56"
  31. label="序号"
  32. :fixed="fixed"
  33. ></el-table-column>
  34. <!-- columnData属性列 -->
  35. <template v-for="item in columnData" :key="item.id">
  36. <el-table-column
  37. v-if="item.type === 'link'"
  38. :label="item.label"
  39. :prop="item.prop"
  40. :width="item.width"
  41. :align="item.align"
  42. :fixed="item.fixed"
  43. :sortable="item.sort"
  44. :formatter="item.formatter"
  45. >
  46. <template #default="scope">
  47. <slot :name="item.prop" v-bind="scope"></slot>
  48. </template>
  49. </el-table-column>
  50. <el-table-column
  51. v-else-if="item.type === 'tag'"
  52. :label="item.label"
  53. :prop="item.prop"
  54. :width="item.width"
  55. :align="item.align"
  56. :fixed="item.fixed"
  57. :sortable="item.sort"
  58. :filters="item.filters"
  59. :filter-method="filterTag"
  60. :formatter="item.formatter"
  61. >
  62. <template #default="scope">
  63. <slot :name="item.prop" v-bind="scope"></slot>
  64. </template>
  65. </el-table-column>
  66. <el-table-column
  67. v-else
  68. :label="item.label"
  69. :prop="item.prop"
  70. :width="item.width"
  71. :align="item.align"
  72. :fixed="item.fixed"
  73. :sortable="item.sort"
  74. :formatter="item.formatter"
  75. >
  76. </el-table-column>
  77. </template>
  78.  </el-table>
  • 实现思路:
1)table的属性和column的属性要分开;
  1. <!--摘自elementPlus表格(基础用法)-->
  2. <template>
  3. <el-table :data="tableData" style="width: 100%">
  4. <el-table-column prop="date" label="Date" width="180" />
  5. <el-table-column prop="name" label="Name" width="180" />
  6. <el-table-column prop="address" label="Address" />
  7. </el-table>
  8. </template>

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

所以子组件内部发展为:

  1.     <el-table
  2. ref="table"
  3. :data="tableData"
  4. >
  5. <!-- columnData属性列 -->
  6. <template v-for="item in columnData" :key="item.id">
  7. <el-table-column
  8. :label="item.label" //每列标题内容参考elemengPlus
  9. :prop="item.prop" //每列字段名称参考elemengPlus
  10. :width="item.width" //每列宽度参考elemengPlus
  11. :align="item.align" //每列对齐方式参考elemengPlus
  12. :fixed="item.fixed" //首列和标题固定参考elemengPlus
  13. :sortable="item.sort" //排序参考elemengPlus
  14. :formatter="item.formatter" //支持内容自定义方法参考elemengPlus
  15. >
  16. </el-table-column>
  17. </template>
  18. </el-table>
  19.     <script setup>
  20.         import {defineProps} from 'vue'
  21.         defineProps({
  22.             tableData:{
  23.                 type:Array
  24.             },
  25.             columnData:{
  26.                 type:Array
  27.             }
  28.         })
  29.     </script>

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

  1.     const columnData = ref([
  2. {
  3. id: 0,
  4. prop: "contractName",
  5. // width: "140",
  6. align: "left",
  7. label: "常规名称长字段",
  8. },
  9. {
  10. id: 1,
  11. prop: "contractDate",
  12. // width: "200",
  13. align: "left",
  14. label: "合同日期",
  15. },
  16. {
  17. id: 2,
  18. prop: "contractAmout",
  19. // width: "130",
  20. align: "right",
  21. label: "合同金额",
  22. sort: true,
  23. formatter: (row) => {
  24. return <div>{row.contractAmout}万</div>;
  25. },
  26. },
  27. {
  28. id: 3,
  29. prop: "contractNum",
  30. // width: "100",
  31. align: "left",
  32. label: "合同编号",
  33. },
  34. {
  35. id: 4,
  36. prop: "operation",
  37. width: "150",
  38. align: "left",
  39. label: "操作",
  40. type: "slot",
  41. formatter: (row,column,cellValue,index) => {
  42. //编辑按钮事件
  43. const handleEdit = (val) => {
  44. console.log('row',row);
  45. console.log('column',column);
  46. console.log('cellValue',cellValue);
  47. console.log('index',index);
  48. // console.log('val',val);
  49. alert(val.contractName);
  50. };
  51. //删除按钮事件
  52. const handleDelete = (val) => {
  53. console.log('row',row);
  54. console.log('column',column);
  55. console.log('cellValue',cellValue);
  56. console.log('index',index);
  57. console.log('row',row);
  58. // console.log('val',val);
  59. alert(val.contractName);
  60. };
  61. return (
  62. <div>
  63. <el-button
  64. type="primary"
  65. size="small"
  66. onClick={() => {
  67. handleEdit(row,column,cellValue,index);
  68. }}
  69. >
  70. 编辑
  71. </el-button>
  72. <el-button
  73. type="danger"
  74. size="small"
  75. onClick={() => {
  76. handleDelete(row,column,cellValue,index);
  77. }}
  78. >
  79. 删除
  80. </el-button>
  81. </div>
  82. );
  83. },
  84. },
  85. ]);
  86. //表格数据的key键名要和columnData中的prop保持一致
  87. const tableData = ref([
  88. {
  89. "id": "1",
  90. "contractName": "医院设备1",
  91. "contractDate": "2023-01-30 14:44:19",
  92. "contractAmout": "50000",
  93. "contractNum": "1",
  94. },
  95. {
  96. "id": "2",
  97. "contractName": "医院设备2",
  98. "contractDate": "2023-01-29 14:44:19",
  99. "contractAmout": "30000",
  100. "contractNum": "2",
  101. },
  102. {
  103. "id": "3",
  104. "contractName": "医院设备3",
  105. "contractDate": "2023-01-28 15:44:19",
  106. "contractAmout": "75000",
  107. "contractNum": "3",
  108. },
  109. {
  110. "id": "4",
  111. "contractName": "医院设备4",
  112. "contractDate": "2023-01-27 15:44:19",
  113. "contractAmout": "80000",
  114. "contractNum": "4",
  115. },
  116. {
  117. "id": "5",
  118. "contractName": "医院设备5",
  119. "contractDate": "2023-01-26 15:44:19",
  120. "contractAmout": "80000",
  121. "contractNum": "5",
  122. },
  123. {
  124. "id": "6",
  125. "contractName": "医院设备6",
  126. "contractDate": "2023-01-25 15:44:19",
  127. "contractAmout": "80000",
  128. "contractNum": "6",
  129. },
  130. {
  131. "id": "7",
  132. "contractName": "医院设备7",
  133. "contractDate": "2023-01-24 15:44:19",
  134. "contractAmout": "80000",
  135. "contractNum": "7",
  136. },
  137. {
  138. "id": "8",
  139. "contractName": "医院设备8",
  140. "contractDate": "2023-01-23 15:44:19",
  141. "contractAmout": "80000",
  142. "contractNum": "8",
  143. },
  144. {
  145. "id": "9",
  146. "contractName": "医院设备9",
  147. "contractDate": "2023-01-22 15:44:19",
  148. "contractAmout": "80000",
  149. "contractNum": "9",
  150. },
  151. {
  152. "id": "10",
  153. "contractName": "医院设备10",
  154. "contractDate": "2023-01-21 15:44:19",
  155. "contractAmout": "80000",
  156. "contractNum": "10",
  157. }
  158. ]);

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

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

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

  1.     <!-- checkbox列 -->
  2. <el-table-column
  3. v-if="selection"
  4. type="selection"
  5. width="56"
  6. align="center"
  7. :fixed="fixed"
  8. >
  9. </el-table-column>
  10. <!-- 序号列 -->
  11. <el-table-column
  12. v-if="index"
  13. type="index"
  14. width="56"
  15. label="序号"
  16. :fixed="fixed"
  17. ></el-table-column>
  18.     <script setup>
  19. import {defineProps} from 'vue'
  20. defineProps({
  21. tableData:{
  22. type:Array
  23. },
  24. columnData:{
  25. type:Array
  26. },
  27.             selection: Boolean,
  28.         index: Boolean,
  29. })
  30. </script>

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

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

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

子组件内部就变成了:

  1.       <!-- columnData属性列 -->
  2. <template v-for="item in columnData" :key="item.id">
  3.         <!-- 扩展列 -->
  4. <el-table-column
  5. v-if="item.type === 'link'"
  6. :label="item.label"
  7. :prop="item.prop"
  8. :width="item.width"
  9. :align="item.align"
  10. :fixed="item.fixed"
  11. :sortable="item.sort"
  12. :formatter="item.formatter"
  13. >
  14. <template #default="scope">
  15. <slot :name="item.prop" v-bind="scope"></slot>
  16. </template>
  17. </el-table-column>
  18.         <!-- 标签列 -->
  19. <el-table-column
  20. v-else-if="item.type === 'tag'"
  21. :label="item.label"
  22. :prop="item.prop"
  23. :width="item.width"
  24. :align="item.align"
  25. :fixed="item.fixed"
  26. :sortable="item.sort"
  27. :filters="item.filters"
  28. :filter-method="filterTag"
  29. :formatter="item.formatter"
  30. >
  31. <template #default="scope">
  32. <slot :name="item.prop" v-bind="scope"></slot>
  33. </template>
  34. </el-table-column>
  35.         <!-- 其他正常列 -->
  36. <el-table-column
  37. v-else
  38. :label="item.label"
  39. :prop="item.prop"
  40. :width="item.width"
  41. :align="item.align"
  42. :fixed="item.fixed"
  43. :sortable="item.sort"
  44. :formatter="item.formatter"
  45. >
  46. </el-table-column>
  47. </template>

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

tag标签插槽:

  1. <template #state="{ row }">
  2. <el-tag v-if="row.state === '进行中'" type="primary">{{
  3. row.state
  4. }}</el-tag>
  5. <el-tag v-if="row.state === '已完成'" type="success">{{
  6. row.state
  7. }}</el-tag>
  8. <el-tag v-if="row.state === '已终止'" type="danger">{{
  9. row.state
  10. }}</el-tag>
  11. <el-tag v-if="row.state === '已中止'" type="warning">{{
  12. row.state
  13. }}</el-tag>
  14. <el-tag v-if="row.state === '已取消'" type="info">{{
  15. row.state
  16. }}</el-tag>
  17. </template>

link扩展链接插槽:

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

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

在父页面使用的时候:

  1.       <!-- 搜索插槽 -->
  2. <template v-slot:search>
  3. <div class="ipt-btn">
  4. <!-- 输入框 -->
  5. <el-row gutter="0">
  6. <!-- 第一行 -->
  7. <el-col :span="8">
  8. <el-form-item label="标题标题">
  9. <el-input
  10. placeholder="请输入"
  11. v-model="form.value1"
  12. @keyup.enter="handleFilter(form)"
  13. />
  14. </el-form-item>
  15. </el-col>
  16. <el-col :span="8">
  17. <el-form-item label="标题标题">
  18. <el-input
  19. placeholder="请输入"
  20. v-model="form.value2"
  21. @keyup.enter="handleFilter(form)"
  22. />
  23. </el-form-item>
  24. </el-col>
  25. <el-col :span="8">
  26. <el-form-item label="标题标题">
  27. <el-input
  28. placeholder="请输入"
  29. v-model="form.value3"
  30. @keyup.enter="handleFilter(form)"
  31. />
  32. </el-form-item>
  33. </el-col>
  34. <!-- 第二行 -->
  35. <el-col :span="8">
  36. <el-form-item label="标题标题" v-show="isShow">
  37. <el-select v-model="form.value5" @change="handleFilter(form)">
  38. <el-option label="选项一" value="选项一">选项一</el-option>
  39. <el-option label="选项二" value="选项二">选项二</el-option>
  40. </el-select>
  41. </el-form-item>
  42. </el-col>
  43. <el-col :span="8">
  44. <el-form-item label="标题标题" v-show="isShow">
  45. <el-date-picker
  46. value-format="YYYY-MM-DD"
  47. placeholder="请选择"
  48. v-model="form.value6"
  49. @change="handleFilter(form)"
  50. ></el-date-picker>
  51. </el-form-item>
  52. </el-col>
  53. <el-col :span="8">
  54. <el-form-item label="标题标题" v-show="isShow">
  55. <el-date-picker
  56. type="datetime"
  57. placeholder="请选择"
  58. v-model="form.value7"
  59. value-format="YYYY-MM-DD HH:mm:ss"
  60. @change="handleFilter(form)"
  61. ></el-date-picker>
  62. </el-form-item>
  63. </el-col>
  64. </el-row>
  65. <!-- 按钮 -->
  66. <div class="btn">
  67. <el-form-item class="btns">
  68. <el-button
  69. class="arrow"
  70. :icon="isShow ? ArrowUp : ArrowDown"
  71. @click="isShow = !isShow"
  72. ></el-button>
  73. <el-button
  74. class="reset"
  75. @click="resetForm"
  76. >重置</el-button
  77. >
  78. <el-button
  79. class="confirm"
  80. type="primary"
  81. @click="onSubmit"
  82. >确定</el-button
  83. >
  84. </el-form-item>
  85. </div>
  86. </div>
  87. </template>
  88.     <script setup>
  89.     import {ref, reactive} from 'vue'
  90.     const isShow = ref(false);
  91.     const form = reactive({
  92.     value1: "张三",
  93.     value2: "10",
  94.     value3: "",
  95.     value4: "",
  96.     value5: "",
  97.     value6: "",
  98.     value7: "",
  99.     });
  100.     </script>

展开效果图:

隐藏效果图:

5)配置分页器

效果图:

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

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

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

  1.     //checkbox点击事件
  2. const instance = getCurrentInstance();
  3. const table = ref(null);
  4. const multipleSelection = ref([]);
  5. const checkNumber = ref(null);
  6. //取消勾选事件
  7. const toggleSelection = () => {
  8. var ultipleTabInstance = toRefs(instance.refs.table);
  9. ultipleTabInstance.clearSelection.value();
  10. };
  11. //勾选checkbox事件
  12. const handleSelectionChange = (val) => {
  13. console.log("val", val);
  14. multipleSelection.value = val;
  15. checkNumber.value = multipleSelection.value.length;
  16. };
(2)父组件
  • 最终代码示例:
  1.     <flex-table
  2. ref="flexTable"
  3. size="large"
  4. disabled
  5. background
  6. prevIcon="ArrowLeft"
  7. nextIcon="ArrowRight"
  8. :url="apiUrl.tableList2"
  9. :requestData="request_data"
  10. :columnData="columnData"
  11. :pageSizes="pageSizes"
  12. fontSize="14px"
  13. fontFamily="PingFangSC-Regular"
  14. labelWidth="110"
  15. selection
  16. border
  17. fixed
  18. >
  19. <!-- 链接插槽 -->
  20. <template #link="{ row }">
  21. <ul class="linkMenu">
  22. <li>
  23. <el-link type="primary" v-if="row.link === 1">催填</el-link>
  24. <el-link type="primary" v-if="row.link === 2">汇总</el-link>
  25. <el-link type="primary" v-if="row.link === 3">重新汇总</el-link>
  26. <el-link type="primary" v-if="row.link === 4">重新确认</el-link>
  27. <el-link type="primary" v-if="row.link === 5">调整</el-link>
  28. </li>
  29. <li>|</li>
  30. <li v-if="row.link === 1">
  31. <el-dropdown>
  32. <span class="el-dropdown-link">
  33. 二级配置
  34. <el-icon class="el-icon--right">
  35. <arrow-down />
  36. </el-icon>
  37. </span>
  38. <template #dropdown>
  39. <el-dropdown-menu>
  40. <el-dropdown-item>更多菜单一</el-dropdown-item>
  41. <el-dropdown-item>更多菜单二</el-dropdown-item>
  42. <el-dropdown-item>更多菜单三</el-dropdown-item>
  43. <el-dropdown-item>更多菜单四</el-dropdown-item>
  44. </el-dropdown-menu>
  45. </template>
  46. </el-dropdown>
  47. </li>
  48. <li v-if="row.link === 2">
  49. <el-dropdown>
  50. <span class="el-dropdown-link">
  51. 上会结束
  52. <el-icon class="el-icon--right">
  53. <arrow-down />
  54. </el-icon>
  55. </span>
  56. <template #dropdown>
  57. <el-dropdown-menu>
  58. <el-dropdown-item>更多菜单一</el-dropdown-item>
  59. <el-dropdown-item>更多菜单二</el-dropdown-item>
  60. <el-dropdown-item>更多菜单三</el-dropdown-item>
  61. <el-dropdown-item>更多菜单四</el-dropdown-item>
  62. </el-dropdown-menu>
  63. </template>
  64. </el-dropdown>
  65. </li>
  66. <li v-if="row.link === 3">
  67. <el-dropdown>
  68. <span class="el-dropdown-link">
  69. 二级配置
  70. <el-icon class="el-icon--right">
  71. <arrow-down />
  72. </el-icon>
  73. </span>
  74. <template #dropdown>
  75. <el-dropdown-menu>
  76. <el-dropdown-item>更多菜单一</el-dropdown-item>
  77. <el-dropdown-item>更多菜单二</el-dropdown-item>
  78. <el-dropdown-item>更多菜单三</el-dropdown-item>
  79. <el-dropdown-item>更多菜单四</el-dropdown-item>
  80. </el-dropdown-menu>
  81. </template>
  82. </el-dropdown>
  83. </li>
  84. <li v-if="row.link === 4">
  85. <el-dropdown>
  86. <span class="el-dropdown-link">
  87. 上会结束
  88. <el-icon class="el-icon--right">
  89. <arrow-down />
  90. </el-icon>
  91. </span>
  92. <template #dropdown>
  93. <el-dropdown-menu>
  94. <el-dropdown-item>更多菜单一</el-dropdown-item>
  95. <el-dropdown-item>更多菜单二</el-dropdown-item>
  96. <el-dropdown-item>更多菜单三</el-dropdown-item>
  97. <el-dropdown-item>更多菜单四</el-dropdown-item>
  98. </el-dropdown-menu>
  99. </template>
  100. </el-dropdown>
  101. </li>
  102. <li v-if="row.link === 5">
  103. <el-dropdown>
  104. <span class="el-dropdown-link">
  105. 二级配置
  106. <el-icon class="el-icon--right">
  107. <arrow-down />
  108. </el-icon>
  109. </span>
  110. <template #dropdown>
  111. <el-dropdown-menu>
  112. <el-dropdown-item>更多菜单一</el-dropdown-item>
  113. <el-dropdown-item>更多菜单二</el-dropdown-item>
  114. <el-dropdown-item>更多菜单三</el-dropdown-item>
  115. <el-dropdown-item>更多菜单四</el-dropdown-item>
  116. </el-dropdown-menu>
  117. </template>
  118. </el-dropdown>
  119. </li>
  120. </ul>
  121. </template>
  122. <!-- 标签插槽 -->
  123. <template #state="{ row }">
  124. <el-tag v-if="row.state === '进行中'">{{ row.state }}</el-tag>
  125. <el-tag v-if="row.state === '已完成'" type="success">{{
  126. row.state
  127. }}</el-tag>
  128. <el-tag v-if="row.state === '已终止'" type="danger">{{
  129. row.state
  130. }}</el-tag>
  131. <el-tag v-if="row.state === '已中止'" type="warning">{{
  132. row.state
  133. }}</el-tag>
  134. <el-tag v-if="row.state === '已取消'" type="info">{{
  135. row.state
  136. }}</el-tag>
  137. </template>
  138. <!-- 搜索插槽 -->
  139. <template v-slot:search>
  140. <div class="ipt-btn">
  141. <!-- 输入框 -->
  142. <el-row gutter="0">
  143. <!-- 第一行 -->
  144. <el-col :span="8">
  145. <el-form-item label="标题标题">
  146. <el-input
  147. placeholder="请输入"
  148. v-model="form.value1"
  149. @keyup.enter="handleFilter(form)"
  150. />
  151. </el-form-item>
  152. </el-col>
  153. <el-col :span="8">
  154. <el-form-item label="标题标题">
  155. <el-input
  156. placeholder="请输入"
  157. v-model="form.value2"
  158. @keyup.enter="handleFilter(form)"
  159. />
  160. </el-form-item>
  161. </el-col>
  162. <el-col :span="8">
  163. <el-form-item label="标题标题">
  164. <el-input
  165. placeholder="请输入"
  166. v-model="form.value3"
  167. @keyup.enter="handleFilter(form)"
  168. />
  169. </el-form-item>
  170. </el-col>
  171. <!-- <el-col :span="6">
  172. <el-form-item label="标题标题">
  173. <el-input
  174. v-model="form.value4"
  175. placeholder="请输入"
  176. @keyup.enter="handleFilter(form)"
  177. ></el-input>
  178. </el-form-item>
  179. </el-col> -->
  180. <!-- 第二行 -->
  181. <el-col :span="8">
  182. <el-form-item label="标题标题" v-show="isShow">
  183. <el-select v-model="form.value5" @change="handleFilter(form)">
  184. <el-option label="选项一" value="选项一">选项一</el-option>
  185. <el-option label="选项二" value="选项二">选项二</el-option>
  186. </el-select>
  187. </el-form-item>
  188. </el-col>
  189. <el-col :span="8">
  190. <el-form-item label="标题标题" v-show="isShow">
  191. <el-date-picker
  192. value-format="YYYY-MM-DD"
  193. placeholder="请选择"
  194. v-model="form.value6"
  195. @change="handleFilter(form)"
  196. ></el-date-picker>
  197. </el-form-item>
  198. </el-col>
  199. <el-col :span="8">
  200. <el-form-item label="标题标题" v-show="isShow">
  201. <el-date-picker
  202. type="datetime"
  203. placeholder="请选择"
  204. v-model="form.value7"
  205. value-format="YYYY-MM-DD HH:mm:ss"
  206. @change="handleFilter(form)"
  207. ></el-date-picker>
  208. </el-form-item>
  209. </el-col>
  210. </el-row>
  211. <!-- 按钮 -->
  212. <div class="btn">
  213. <el-form-item class="btns">
  214. <el-button
  215. style="
  216. width: 30px;
  217. height: 34px;
  218. background: #eef1f5;
  219. borderradius: 4px;
  220. "
  221. class="arrow"
  222. :icon="isShow ? ArrowUp : ArrowDown"
  223. @click="isShow = !isShow"
  224. ></el-button>
  225. <el-button
  226. class="reset"
  227. @click="resetForm"
  228. style="
  229. width: 50px;
  230. height: 34px;
  231. border: 1px solid rgba(0, 0, 0, 0.2);
  232. border-radius: 4px;
  233. "
  234. >重置</el-button
  235. >
  236. <el-button
  237. class="confirm"
  238. type="primary"
  239. @click="onSubmit"
  240. style="
  241. width: 50px;
  242. height: 34px;
  243. background: #3480FB;
  244. border-radius: 4px;
  245. "
  246. >确定</el-button
  247. >
  248. </el-form-item>
  249. </div>
  250. </div>
  251. </template>
  252. </flex-table>
  253. </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文件夹;

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

  1. {
  2. "totalElements":10, //总条数
  3. "page":1, //当前页码
  4. "rows":5, //每行显示条数
  5. "content":[
  6. {
  7. "id": "1",
  8. "contractName": "医院设备1",
  9. "contractDate": "2023-01-30 14:44:19",
  10. "contractAmout": "50000",
  11. "contractNum": "1",
  12. },
  13. {
  14. "id": "2",
  15. "contractName": "医院设备2",
  16. "contractDate": "2023-01-29 14:44:19",
  17. "contractAmout": "30000",
  18. "contractNum": "2",
  19. },
  20. {
  21. "id": "3",
  22. "contractName": "医院设备3",
  23. "contractDate": "2023-01-28 15:44:19",
  24. "contractAmout": "75000",
  25. "contractNum": "3",
  26. },
  27. {
  28. "id": "4",
  29. "contractName": "医院设备4",
  30. "contractDate": "2023-01-27 15:44:19",
  31. "contractAmout": "80000",
  32. "contractNum": "4",
  33. },
  34. {
  35. "id": "5",
  36. "contractName": "医院设备5",
  37. "contractDate": "2023-01-26 15:44:19",
  38. "contractAmout": "80000",
  39. "contractNum": "5",
  40. },
  41. {
  42. "id": "6",
  43. "contractName": "医院设备6",
  44. "contractDate": "2023-01-25 15:44:19",
  45. "contractAmout": "80000",
  46. "contractNum": "6",
  47. },
  48. {
  49. "id": "7",
  50. "contractName": "医院设备7",
  51. "contractDate": "2023-01-24 15:44:19",
  52. "contractAmout": "80000",
  53. "contractNum": "7",
  54. },
  55. {
  56. "id": "8",
  57. "contractName": "医院设备8",
  58. "contractDate": "2023-01-23 15:44:19",
  59. "contractAmout": "80000",
  60. "contractNum": "8",
  61. },
  62. {
  63. "id": "9",
  64. "contractName": "医院设备9",
  65. "contractDate": "2023-01-22 15:44:19",
  66. "contractAmout": "80000",
  67. "contractNum": "9",
  68. },
  69. {
  70. "id": "10",
  71. "contractName": "医院设备10",
  72. "contractDate": "2023-01-21 15:44:19",
  73. "contractAmout": "80000",
  74. "contractNum": "10",
  75. }
  76. ]
  77. }
  78. ]
  79. }

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

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

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

import './mock/index'

(3),步骤三:封装axios请求,新建api文件夹
  1. import axios from 'axios';
  2. import {ElMessage} from 'element-plus';
  3. //请求表格数据
  4. const getTableData = (url, data)=>{
  5. console.log('post请求参数',data);
  6. return axios({
  7. method:'post',
  8. url:url,
  9. data:data
  10. }).then(
  11. res => {
  12. return res.data
  13. },
  14. error => {
  15. ElMessage({
  16. type:'error',
  17. message:error.message,
  18. showClose: true
  19. })
  20. }
  21. )
  22. }
  23. export default getTableData
(4),步骤四:组件中引入方法请求数据

组件代码:

  1. import getTableData from "../api/table";
  2. props: {
  3. //外部传入url,但也需要给个默认值
  4. url: {
  5. type: String,
  6. require: true,
  7. default: "/getData",
  8. },
  9. }
  10. //get请求数据方法
  11. const getTableList = (url, options) => {
  12. //判断url不存在不继续进行请求
  13. if (!url) {
  14. console.log("请求地址不存在!");
  15. return false;
  16. }
  17. getTableData(url, options).then((res) => {
  18. console.log("res", res);
  19.     const { data } = res;
  20.       //处理请求数据内容渲染表格
  21. tableData.value = data.content;
  22. });
  23. };
  24. onMounted(() => {
  25. getTableList(props.url, props.requestData);
  26. });

使用父页面:

  1. <flex-table
  2.     url="/getData"
  3.     :columnData="columnData"
  4. ></flex-table>

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

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

(1)步骤一:tableData.json数据中添加分页器参数
  1. "totalElements":10, //总条数
  2. "page":1, //当前页码
  3. "rows":5, //每行显示条数
(2)步骤二:组件内处理请求参数
  1. <el-pagination
  2. :small="small" //是否启用小型分页器字号12px
  3. :background="background" //页码选中是否有背景色
  4. layout="total, prev, pager, next, sizes, jumper" //分页器各组件
  5. :total="total" //总条数
  6. :pager-count="4" //设置最大按钮数
  7. :page-size="pageSize" //每页显示条数
  8. :page-sizes="pageSizes" //每页显示个数选择器的选项设置
  9. @size-change="sizeChange" //page-size 改变时触发
  10. @current-change="handleCurrentChange" //页码发生变化触发事件
  11. />
  1. const total = ref(10); //总条数,可以给个默认值
  2. const pageSize = ref(10); //每页条数,可以给个默认值
  3. const currentPage = ref(1); //当前页码,可以给个默认值
  4. //get请求数据方法
  5. const getTableList = (url, options) => {
  6. //判断url不存在不继续进行请求
  7. if (!url) {
  8. console.log("请求地址不存在!");
  9. return false;
  10. }
  11. getTableData(url, options).then((res) => {
  12. console.log("res", res);
  13. const { data } = res;
  14. //处理请求数据内容渲染表格
  15. tableData.value = data.content;
  16.      //处理请求数据总条数 ---后端给的
  17. total.value = data.totalElements;
  18. //处理请求每页显示条数 ---后端给的
  19. pageSize.value = data.rows;
  20. //处理请求当前显示页码 ---后端给的
  21. currentPage.value = data.page;
  22. });
  23. };
(3)步骤三:处理页码变化时,传入相应的值给参数进行请求数据

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

  1. <flex-table
  2. url="/getData"
  3. :columnData="columnData"
  4.     :requestData="request_data"
  5. ></flex-table>
  6. <script>
  7.     const request_data = reactive({
  8.     page: 1, //当前页码
  9.     rows: 10, //每页显示条数
  10.     searchVal: {}, //搜索框输入的值
  11.     });
  12. </script>
  1.     import {
  2.     ref,
  3.     computed,
  4.     onMounted,
  5.     getCurrentInstance,
  6.     toRefs,
  7.     defineExpose,
  8.     defineEmits,
  9.     } from "vue";
  10.    
  11.     props: {
  12.         //分页器请求参数
  13.         requestData: {
  14.     type: Object,
  15.     default: () => ({
  16.     page: 1, //当前页数
  17.     rows: 10, //显示条数
  18.     searchVal: {}, //搜索框的值
  19.     }),
  20.     },
  21.     }
  22.     //处理props值可以重新赋值
  23.     const emits = defineEmits();   
  24.     const pageParams = computed({
  25.     get: () => {
  26.     return props.requestData;
  27.     },
  28.     set: (val) => {
  29.     emits("update:requestData", val);
  30.     },
  31.     });
  32.     //当前页码变化事件
  33. const handleCurrentChange = (val) => {
  34.       //把当前页码赋值给请求参数
  35. pageParams.value.page = val;
  36.       //请求数据
  37. getTableList(props.url, pageParams.value);
  38. };
  39. //每页显示条数变化事件
  40. const sizeChange = (val) => {
  41.       //把变化的每页显示条数赋值给请求参数
  42. pageParams.value.rows = val;
  43.       //请求数据
  44. getTableList(props.url, pageParams.value)
  45. };
  46.     //上一页点击事件
  47. const handlePreClick = (val) => {
  48. console.log(`handlePreClick,点击了上一页,当前第${val}页`);
  49. };
  50.     //下一页点击事件
  51. const handleNextClick = (val) => {
  52. console.log(`handleNextClick,点击了下一页,当前第${val}页`);
  53. };

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

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

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

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

  1. import tableData1 from './mockData/tableData1.json'
  2. import tableData2 from './mockData/tableData2.json'
  3. Mock.mock("/getData",(config)=>{
  4. let params = JSON.parse(config.body)
  5. //如果当前页码 = 2,返回第二页数据
  6. if(params.page == 2){
  7. return {
  8. success: true,
  9. data: tableData1,
  10. }
  11. }else if(params.page == 1){
  12.     //如果当前页码 = 1,返回第一页数据
  13. return {
  14. success: true,
  15. data: tableData2,
  16. };
  17. }
  18. })

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

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

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

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

五,注意说明

1,关于代码写法

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

  1. <sctipt>
  2. export default{
  3.     name:"组件名"
  4. }
  5. </script>
  6. <sctipt setup>
  7.     //正常业务代码
  8. </script>

2,关于组件内其他属性

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

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

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

4,关于对接真实接口

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

5,关于组件需求

不同业务或许有不同的组件封装需求,以上主要是提供一些需求的一种解决方案,大家可以灵活参考。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/701632
推荐阅读
相关标签
  

闽ICP备14008679号