Element Table实现用户自定义列

我就是我 2022-09-12 01:43 655阅读 0赞

需求:文件列表用户自定义

基础:之前已经实现了文件列表的功能,但是是固定表头的列表

期初,我们是根据用户提出的要求展示相应的列,没有做过多的考虑,因此,我们当时直接固定了列名。这样做其实大大限制了程序的可扩展性,如果用户使用过程中发现我需要的没有这么多列或者我想要更多的列的时候怎么办?只能改代码,严重违反了软件设计的开放封闭的原则,因此,在功能设计的时候要考虑的全面一点,不能不听用户的,但是也不能全听用户的,要有全局观。

基础代码实现:

当el-table元素中注入data对象数组后,在el-table-column中用prop属性来对应对象中的键名即可填入数据,用label属性来定义表格的列名。可以使用width属性来定义列宽。

  1. <el-table
  2. //绑定对象数组
  3. :data="tableData"
  4. //带斑马纹的表格
  5. stripe
  6. //带有纵向边框
  7. border
  8. class="table"
  9. //当某一行被点击时会触发该事件
  10. @row-click="openDetails"
  11. >
  12. <el-table-column
  13. //对应列内容的字段名,
  14. prop="projectname"
  15. //列宽
  16. width="100"
  17. //显示的标题
  18. label="项目名"
  19. show-overflow-tooltip
  20. ></el-table-column>
  21. <el-table-column
  22. prop="name"
  23. width="100"
  24. label="文件名"
  25. show-overflow-tooltip
  26. ></el-table-column>
  27. <el-table-column
  28. prop="type"
  29. width="100"
  30. label="文件类型"
  31. show-overflow-tooltip
  32. ></el-table-column>
  33. <el-table-column
  34. prop="url"
  35. width="350"
  36. label="文件地址"
  37. show-overflow-tooltip
  38. ></el-table-column>
  39. <el-table-column
  40. label="操作"
  41. width="200"
  42. align="center"
  43. show-overflow-tooltip
  44. >
  45. <template slot-scope="scope">
  46. <div
  47. v-if="
  48. ['video', 'application', 'audio', 'pdf'].includes(
  49. scope.row.type
  50. )
  51. "
  52. >
  53. <el-button
  54. type="text"
  55. icon="el-icon-plus"
  56. @click="addQuestion(scope.row)"
  57. >添加问题</el-button
  58. >
  59. <el-button
  60. type="text"
  61. icon="el-icon-delete"
  62. @click="deleteFile(scope.$index, scope.row)"
  63. >删除文件</el-button
  64. >
  65. </div>
  66. <div v-else>
  67. <el-button type="text" icon="el-icon-plus" disabled
  68. >添加问题</el-button
  69. >
  70. <el-button type="text" icon="el-icon-delete" disabled
  71. >删除文件</el-button
  72. >
  73. </div>
  74. </template>
  75. </el-table-column>
  76. </el-table>

js:

里面包含一些分页逻辑,之前的总结中已经写过element Table+Pagination实现分页_灵活的小胖子-CSDN博客

  1. handleSearch(pageNum) {
  2. if (pageNum) {
  3. this.query.pageNum = 1;
  4. }
  5. this.tableData = [];
  6. Search(this.query).then((res) => {
  7. var result = res.result;
  8. this.dataList = result.informationData;
  9. this.total = result.informationCount;
  10. for (let i = 0; i < this.dataList.length; i++) {
  11. var o = new Object();
  12. o.name = this.dataList[i].name;
  13. o.type = this.dataList[i].type;
  14. o.length = this.dataList[i].length;
  15. o.projectname = this.dataList[i].projectname;
  16. o.url = this.dataList[i].url;
  17. this.tableData.push(o);
  18. }
  19. });
  20. },

实现效果:

watermark_type_ZHJvaWRzYW5zZmFsbGJhY2s_shadow_50_text_Q1NETiBA54G15rS755qE5bCP6IOWemhp_size_20_color_FFFFFF_t_70_g_se_x_16

优化:有了前车之鉴,我们直接将文件列表设计成用户自定义的岂不是更好,让用户决定显示什么不显示什么,做到让软件的使用者成为软件的设计者

首先,我们列出供用户选择的全部的列,我是将整个表的列和列注释(给用户看的一定不能是英文)都查出来

  1. //sql
  2. select COLUMN_NAME "columns",COLUMN_COMMENT "remark" from information_schema.COLUMNS where table_name = 't_information'
  3. //调用后端方法
  4. handleSet(){
  5. SelectAllColumns().then((res) => {
  6. this.columnsList=res.result
  7. });
  8. },

渲染到前端:

关于用户自定义列的选择框:

样式:小编这里用的是一个弹出框里面套一个卡片的形式实现的(主要是偷懒,嘻嘻),大家可以根据自己的需要来

数据存储形式:由于数据库是不会轻易改变的,因此数据库表里的列查出来之后可以存储在redis里或存储在前端缓存里,提高程序的性能;如果列数不是很多的话,每次去查也不会影响性能,根据实际项目情况来即可

  1. <el-popover
  2. class="box"
  3. title="自定义表单项"
  4. placement="top-start"
  5. width="290"
  6. trigger="click"
  7. >
  8. <el-card class="box-card">
  9. <el-checkbox-group v-model="checkedList">
  10. <el-checkbox
  11. //循环我们查询到的列
  12. v-for="column in columnsList"
  13. :key="column.index"
  14. :label="column.remark"
  15. >{
  16. { column.remark }}</el-checkbox
  17. >
  18. </el-checkbox-group>
  19. <el-row :gutter="60" style="margin-top: 10px; margin-left: -12%">
  20. <el-col :span="10"
  21. ><el-button type="primary" @click="save()"
  22. >保存</el-button
  23. ></el-col>
  24. <el-col :span="13"><el-button @click="restoreDefault">恢复默认</el-button> </el-col>
  25. </el-row>
  26. </el-card>
  27. <el-button
  28. slot="reference"
  29. type="text"
  30. icon="el-icon-s-tools"
  31. @click="handleSet"
  32. ></el-button>
  33. </el-popover>

效果:

初始化时默认勾选下面的三个,后期可以根据用户的选择进行优化,记录用户行为数据,比如大部分用户都想看某某列,初始化的时候就勾选相应的列

watermark_type_ZHJvaWRzYW5zZmFsbGJhY2s_shadow_50_text_Q1NETiBA54G15rS755qE5bCP6IOWemhp_size_7_color_FFFFFF_t_70_g_se_x_16

我们还要做一个转换,用户选择的是中文的列,但是我们去库中查询的是数据库对应的英文名的列,也为了更方便和Table组件的prop做对应,因此需要我们拿到我们选择的中文的列名,然后遍历之前查到的所有的列后端返回的列和列的注释,最后得到英文的列名

  1. for(let a=0;a<this.checkedList.length;a++){
  2. for(let b=0;b<this.columnsList.length;b++){
  3. var cols = new Object();
  4. if(this.checkedList[a]==this.columnsList[b].remark){
  5. cols.columns=this.columnsList[b].columns;
  6. cols.remark=this.columnsList[b].remark;
  7. this.colsList.push(cols);
  8. }
  9. }
  10. }
  11. this.checkedListNew=[]
  12. this.checkedListNew= this.colsList

下面就是根据用户选择的列展示数据:

  1. <el-table
  2. :data="tableData"
  3. stripe
  4. border
  5. class="table"
  6. ref="multipleTable"
  7. @row-click="openDetails"
  8. header-cell-class-name="table-header"
  9. resizable=true
  10. >
  11. <template v-for="(item, index) in checkedListNew">
  12. //这是基础样式项
  13. <el-table-column
  14. :prop="item.columns"
  15. :label="item.remark"
  16. :key="index"
  17. align="center"
  18. show-overflow-tooltip
  19. width="120"
  20. >
  21. </el-table-column>
  22. </template>
  23. <el-table-column
  24. label="操作"
  25. width="200"
  26. align="center"
  27. show-overflow-tooltip
  28. >
  29. <template slot-scope="scope">
  30. <div
  31. v-if="
  32. ['video', 'application', 'audio', 'pdf'].includes(
  33. scope.row.type
  34. )
  35. "
  36. >
  37. <el-button
  38. type="text"
  39. icon="el-icon-plus"
  40. class="blue"
  41. @click="addQuestion(scope.row)"
  42. >添加问题</el-button
  43. >
  44. <el-button
  45. type="text"
  46. icon="el-icon-delete"
  47. @click="deleteFile(scope.$index, scope.row)"
  48. >删除文件</el-button
  49. >
  50. </div>
  51. <div v-else>
  52. <el-button type="text" icon="el-icon-plus" disabled
  53. >添加问题</el-button
  54. >
  55. <el-button type="text" icon="el-icon-delete" disabled
  56. >删除文件</el-button
  57. >
  58. </div>
  59. </template>
  60. </el-table-column>
  61. </el-table>
  62. handleSearch(pageNum) {
  63. if (pageNum) {
  64. this.query.pageNum = 1;
  65. }
  66. this.tableData = [];
  67. Search(this.query).then((res) => {
  68. var result = res.result;
  69. this.dataList = result.informationData;
  70. this.total = result.informationCount;
  71. this.tableData=this.dataList
  72. });
  73. },

有没有觉得熟悉,跟没有用户自定义代码很类似。

html:

之前的列是固定的,列名可以直接写好;现在列是不固定的,是根据用户选择的,因此要根据用户选择循环出所有的列

js:

之前我们对后端返回数据进行处理,只拿需要现实的列并且赋值存到一个新定义的list里,我们做了一下优化,其实可以不用这么麻烦的,只要定义好prop(对应列内容的字段名)和我们后端返回的字段能对应上既可以展示相应的列,让它自己挑选能对应的数据,不用我们重新赋值,减少了赋值过程中可能产生的错误也避免了代码的冗余

前面只说了用户选择的列,那如果不是用户选择的呢,是固定的呢?就拿我们的操作一列来说。通过设置 Scoped slot 来自定义表头:

  1. <template slot-scope="scope">
  2. <div
  3. v-if="
  4. ['video', 'application', 'audio', 'pdf'].includes(
  5. scope.row.type
  6. )
  7. "
  8. >
  9. <el-button
  10. type="text"
  11. icon="el-icon-plus"
  12. class="blue"
  13. @click="addQuestion(scope.row)"
  14. >添加问题</el-button
  15. >
  16. <el-button
  17. type="text"
  18. icon="el-icon-delete"
  19. @click="deleteFile(scope.$index, scope.row)"
  20. >删除文件</el-button
  21. >
  22. </div>
  23. <div v-else>
  24. <el-button type="text" icon="el-icon-plus" disabled
  25. >添加问题</el-button
  26. >
  27. <el-button type="text" icon="el-icon-delete" disabled
  28. >删除文件</el-button
  29. >
  30. </div>
  31. </template>

我们这里的操作还做了限制,如果列表中type的类型满足条件即操作里的按钮可用,否则不可用,那么问题来了—-

思考:如果用户自定义列的时候不选择type类型,操作列的数据会怎样展示?为什么?

还有一个问题:用户自定义列,用户选择的列可能很多,可能很少,这个时候前端页面应该怎样控制列的宽度呢?

总结:小编作为一个初学者,功能可能只是实现了效果,待优化的地方还有很多,希望大家多提宝贵意见~~~

发表评论

表情:
评论列表 (有 0 条评论,655人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Element Table实现用户定义

    需求:文件列表用户自定义 基础:之前已经实现了文件列表的功能,但是是固定表头的列表 期初,我们是根据用户提出的要求展示相应的列,没有做过多的考虑,因此,我们当时直接固定了列