• 售前

  • 售后

热门帖子
入门百科

element el-table表格的二次封装实现(附表格高度自顺应)

[复制链接]
螃蟹357 显示全部楼层 发表于 2021-10-25 19:33:17 |阅读模式 打印 上一主题 下一主题
媒介


在公司练习使用vue+element-ui框架进行前端开发,使用表格el-table较为多,有些业务逻辑比较相似,有些地方使用的重复性高,假如多个页面使用雷同的功能,就要多次重复写逻辑上差不多的代码,以是计划对表格这个组件进行封装,将雷同的代码和逻辑封装在一起,把差别的业务逻辑抽离出来。话不多说,下面就来实现一下吧。

一、原生el-tbale代码——简朴の封装


这里直接引用官方的底子使用模板,直接抄过来(✪ω✪),下面代码中主要是抽离html部分,可以看出每个el-table-column中都含有prop、label、width属性,只不外这些属性值不太一样罢了,别的的部分都差不多一样,以是表头(表格每列el-table-column的界说)这里可以封装一下,把差别的地方封装成一个数组对象结构,然后通过for循环来完成html中的部分。
封装前
  1. <template>
  2.   <el-table
  3.    :data="tableData"
  4.    style="width: 100%">
  5.    <el-table-column
  6.     prop="date"
  7.     label="日期"
  8.     width="180">
  9.    </el-table-column>
  10.    <el-table-column
  11.     prop="name"
  12.     label="姓名"
  13.     width="180">
  14.    </el-table-column>
  15.    <el-table-column
  16.     prop="address"
  17.     label="地址">
  18.    </el-table-column>
  19.   </el-table>
  20. </template>
  21. <script>
  22.   export default {
  23.    data() {
  24.     return {
  25.      tableData: [{
  26.       date: '2016-05-02',
  27.       name: '王小虎',
  28.       address: '上海市普陀区金沙江路 1518 弄'
  29.      }, {
  30.       date: '2016-05-04',
  31.       name: '王小虎',
  32.       address: '上海市普陀区金沙江路 1517 弄'
  33.      }, {
  34.       date: '2016-05-01',
  35.       name: '王小虎',
  36.       address: '上海市普陀区金沙江路 1519 弄'
  37.      }, {
  38.       date: '2016-05-03',
  39.       name: '王小虎',
  40.       address: '上海市普陀区金沙江路 1516 弄'
  41.      }]
  42.     }
  43.    }
  44.   }
  45. </script>
复制代码
表格の样子

封装后
  1. <template>
  2. <el-table :data="tableData" style="width: 100%">
  3.   <template v-for="(item, key) in header">
  4.    <el-table-column
  5.     :key="key"
  6.     :prop="itm.prop ? itm.prop : null"
  7.     :label="itm.label ? itm.label : null"
  8.     :width="itm.width ? itm.width : null"
  9.    >
  10.    </el-table-column>
  11.   </template>
  12. </el-table>
  13. </template>
  14. <script>
  15. export default {
  16. data() {
  17.   return {
  18.    header: [
  19.     { prop: "date", label: "日期", width: "180" },
  20.     { prop: "name", label: "姓名", width: "180" },
  21.     { prop: "address", label: "地址" }
  22.    ],
  23.    tableData: [
  24.     {
  25.      date: "2016-05-02",
  26.      name: "王小虎",
  27.      address: "上海市普陀区金沙江路 1518 弄"
  28.     },
  29.     {
  30.      date: "2016-05-04",
  31.      name: "王小虎",
  32.      address: "上海市普陀区金沙江路 1517 弄"
  33.     },
  34.     {
  35.      date: "2016-05-01",
  36.      name: "王小虎",
  37.      address: "上海市普陀区金沙江路 1519 弄"
  38.     },
  39.     {
  40.      date: "2016-05-03",
  41.      name: "王小虎",
  42.      address: "上海市普陀区金沙江路 1516 弄"
  43.     }
  44.    ]
  45.   };
  46. }
  47. };
  48. </script>
复制代码
现在数据还比较少,大概看不出封装组件封装的上风,但是相对于之前代码,这里逻辑上看起来更加清楚,而且修改列的时候直接改动data中的header数据即可,不消再去html代码中去“开刀”( ̄▽ ̄)/。上面是最最最简朴的封装了,严酷来说只是简朴的抽离了一下代码中的数据结构,在正常的业务中肯定不止这么简朴的封装,接下来才是重点─━ _ ─━✧

二、el-tbale代码——复杂の封装


在真正的开发过程中,表格不光仅要展示数据,还要完成一些额外的任务,好比CRUD(增编削查操纵)和数据格式转化,表格内每一条数据都有大概被单独修改大概实行一些功能性的交互,这时候就要在单元格内内嵌一些按钮、输入框、标签等等的代码,element官方给出的方法是使用插槽slot,获取对应行的数据使用slot-scope,在对应的列中设置相应的代码,但是这里给我们二次封装就会带来不小的标题,假如只是单纯的修改数据的格式使用官方提供的formatter属性还可以实现,但是要内嵌代码就会比较麻烦,内嵌代码一定就会带来封装上的困难,这也是我在封装代码的时候碰到的最大的拦阻,假如要想封装好这个表格,就必须将这部分代码抽离出组件外,在查询阅读了大量博客之后(实在是我菜了,学艺不精(T▽T)),我终于找到了将内嵌代码剥离出组件的方法ヾ(๑╹◡╹)ノ",那就是render函数,关于render可以参考一下这篇博客,使用render函数就可以轻而易举的将这部分逻辑代码抽离出来了。

el-table真正の二次封装
二次封装源代码
  1. <template>
  2. <el-table
  3.   empty-text="暂无数据"
  4.   ref="table"
  5.   :data="tableList"
  6.   border
  7.   stripe
  8.   fit
  9.   highlight-current-row
  10.   :height="inTableHeight"
  11.   @selection-change="selectionChange"
  12.   @row-click="rowClick"
  13. >
  14.   <!-- 选择框 -->
  15.   <el-table-column
  16.    v-if="select"
  17.    type="selection"
  18.    fixed="left"
  19.    width="55"
  20.    align="center"
  21.   />
  22.   <template v-for="(itm, idx) in header">
  23.    <!-- 特殊处理列 -->
  24.    <el-table-column
  25.     v-if="itm.render"
  26.     :key="idx"
  27.     :prop="itm.prop ? itm.prop : null"
  28.     :label="itm.label ? itm.label : null"
  29.     :width="itm.width ? itm.width : null"
  30.     :sortable="itm.sortable ? itm.sortable : false"
  31.     :align="itm.align ? itm.align : 'center'"
  32.     :fixed="itm.fixed ? itm.fixed : null"
  33.     :show-overflow-tooltip="itm.tooltip"
  34.     min-width="50"
  35.    >
  36.     <template slot-scope="scope">
  37.      <ex-slot
  38.       :render="itm.render"
  39.       :row="scope.row"
  40.       :index="scope.$index"
  41.       :column="itm"
  42.      />
  43.     </template>
  44.    </el-table-column>
  45.    <!-- 正常列 -->
  46.    <el-table-column
  47.     v-else
  48.     :key="idx"
  49.     :prop="itm.prop ? itm.prop : null"
  50.     :label="itm.label ? itm.label : null"
  51.     :width="itm.width ? itm.width : null"
  52.     :sortable="itm.sortable ? itm.sortable : false"
  53.     :align="itm.align ? itm.align : 'center'"
  54.     :fixed="itm.fixed ? itm.fixed : null"
  55.     :formatter="itm.formatter"
  56.     :show-overflow-tooltip="itm.tooltip"
  57.     min-width="50"
  58.    />
  59.   </template>
  60. </el-table>
  61. </template>
  62. <script>
  63. // 自定义内容的组件
  64. var exSlot = {
  65. functional: true,
  66. props: {
  67.   row: Object,
  68.   render: Function,
  69.   index: Number,
  70.   column: {
  71.    type: Object,
  72.    default: null
  73.   }
  74. },
  75. render: (h, context) => {
  76.   const params = {
  77.    row: context.props.row,
  78.    index: context.props.index
  79.   };
  80.   if (context.props.column) params.column = context.props.column;
  81.   return context.props.render(h, params);
  82. }
  83. };
  84. export default {
  85. components: { exSlot },
  86. props: {
  87.   tableList: {
  88.    type: Array,
  89.    default: () => []
  90.   },
  91.   header: {
  92.    type: Array,
  93.    default: () => []
  94.   },
  95.   select: {
  96.    type: Boolean,
  97.    default: () => false
  98.   },
  99.   height: {
  100.    type: [Number, String, Function],
  101.    default: () => null
  102.   }
  103. },
  104. data() {
  105.   return {
  106.    inTableHeight: null
  107.   };
  108. },
  109. created() {
  110.   //该阶段可以接收父组件的传递参数
  111.   this.inTableHeight = this.height;
  112. },
  113. mounted() {
  114.   this.$nextTick(() => {
  115.    //表格高度自适应浏览器大小
  116.    this.changeTableHight();
  117.    if (!this.height) {
  118.     window.onresize = () => {
  119.      this.changeTableHight();
  120.     };
  121.    }
  122.   });
  123. },
  124. destroyed() {
  125.   //高度自适应事件注销
  126.   window.onresize = null;
  127. },
  128. watch: {
  129.   /**
  130.    * 数据变化后 高度自适应
  131.    */
  132.   tableList() {
  133.    this.$nextTick(() => {
  134.     this.changeTableHight();
  135.    });
  136.   }
  137. },
  138. methods: {
  139.   /**
  140.    * 选择框选择后更改,事件分发
  141.    */
  142.   selectionChange(selection) {
  143.    this.$emit("selection-change", selection);
  144.   },
  145.   /**
  146.    * 点击事件
  147.    */
  148.   rowClick(row, column, event) {
  149.    this.$emit("row-click", row, column, event);
  150.   },
  151.   /**
  152.    * 高度自适应
  153.    * 当表格展示空间小于460按460px展示,大于的时候高度填充
  154.    */
  155.   changeTableHight() {
  156.    if (this.height) {
  157.     //如果有传进来高度就取消自适应
  158.     this.inTableHeight = this.height;
  159.     this.$refs.table.doLayout();
  160.     return;
  161.    }
  162.    let tableHeight = window.innerHeight || document.body.clientHeight;
  163.    //高度设置
  164.    let disTop = this.$refs.table.$el;
  165.    //如果表格上方有元素则减去这些高度适应窗口,66是底下留白部分
  166.    tableHeight -= disTop.offsetTop + 66;
  167.    if (disTop.offsetParent) tableHeight -= disTop.offsetParent.offsetTop;
  168.    this.inTableHeight = tableHeight < 460 ? 460 : tableHeight;
  169.    //重绘表格
  170.    this.$refs.table.doLayout();
  171.   }
  172. }
  173. };
  174. </script>
  175. <style></style>
复制代码
封装代码的相关表明
以上就是我封装的代码,部分属性大概方法由于没有使用到以是我就没有将对应的方法和属性封装进去,假如你们开发中有效到对应的地方实在可以照猫画虎的填上去即可,我封装表格的时候在属性这里使用了三目运算符,用于做一些兼容,假如不传对应的属性就给个默认值,好比align属性,我设置的是默认居中。另有就是方法,在表格的方法引用方面,实在就是把官方的方法用$emit变乱将对应的参数和方法名用同样的方法分发给父组件,这样父组件使用完全可以参照element官方文档使用这些方法,在组件内我只是进行了一次转发而已,我本身写的时候并没有效到太多的方法,以是只封装了一两个,假如有必要可以自行添加。除了上述两个封装,有一个特别的地方就是勾选框,不能放在循环内,否则会出现错误,大概是索引的标题吧,以是我单独使用一个参数来控制是否表现选择框。别的就是,在公司产物要求表格能够自顺应页面的高度,这个功能我也是修改了很久,460是最小的高度,关于高度自顺应的全部在changeTableHight()方法中,假如不必要这个功能,将函数和全部引用该函数的地方删除即可。

height:假如不传入这个属性,那么表格高度就如上面所说的是自顺应高度,可以通过这个属性来指定表格的高度。
formatter:这个属性在列中假如使用插槽就会失效,以是我设置了两个列,假如有render方法阐明单元格要内嵌代码,就是用特别列,反之就是正常列,以是formatter和render不能同时使用。

render:终于到了最关键的地方了( ̄▽ ̄)/,这个但是我封装表格的最浩劫点了,render对我个人明白而言就是假造结点,在DOM和CSSOM树归并为render树的阶段,对代码进行修改。

以上就是我封装表格的详细表明了,大概有遗漏的部分,究竟封装这个表格也让我学了不少东西,以是之前有些地方大概表明不清楚大概不到位,还望各位大佬指正。

三、父组件引用封装的组件


封装这么久的组件,固然要使用起来才知道的到底好欠好用,关于引用方面,起首要在引用的地方进行组件注册,假如全局注册过了,可以忽略在局部注册,关于组件的注册这里就不做详解了(o゚▽゚)o  。我使用了全局注册,以是这里是直接引入我本身封装好的组件。
  1. <template>
  2. <div class="hello">
  3.   <xd-table :table-list="tableData" :header="header" height="300"></xd-table>
  4. </div>
  5. </template>
  6. <script>
  7. export default {
  8. name: "HelloWorld",
  9. data() {
  10.   return {
  11.    header: [
  12.     { prop: "w", label: "w" },
  13.     { prop: "x", label: "x",
  14.      formatter: (row) => {
  15.       return row.x.toFixed(3);
  16.      },
  17.     },
  18.     { prop: "d", label: "d",
  19.      formatter: (row) => {
  20.       return row.d.toFixed(2);
  21.      },
  22.     },
  23.     {
  24.      label: "操作",
  25.      render: (h, data) => {
  26.       return (
  27.        <el-button
  28.         type="primary"
  29.         onClick={() => {
  30.          this.handleClick(data.row);
  31.         }}
  32.        >
  33.         点我获取行数据
  34.        </el-button>
  35.       );
  36.      },
  37.     },
  38.    ],
  39.    tableData: [
  40.     { w: 1, x: 99.25123, d: 0.23892 },
  41.     { w: 1, x: 255.6666, d: 0.99134 },
  42.    ],
  43.   };
  44. },
  45. methods: {
  46.   handleClick(row) {
  47.    console.log(row);
  48.   },
  49. },
  50. };
  51. </script>
复制代码
引用组件之前肯定要记得先注册,这里我只使用了几个属性,其他属性没有使用,由于是demo,主要照旧展示render内嵌代码的方法,另有一个就是官方formatter方法的使用。
有一个必要注意点就是render内我使用了JSX模板语法这里必要在VUE项目中单独去设置一下JSX语法,假如不想使用JSX,直接写也可以,由于不使用JSX语法写出来的内嵌模板代码比较难读以是我就不展示了,个人发起照旧使用JSX语法,虽然和原生vue有些地方使用方法不太一样。
效果截图


结语


这次封装vue组件,花了我快要半个月的时间,从刚开始的打仗到发现bug然后去修改,来往返回终于精简封装出现在这个二次封装的组件,大概对于熟悉vue和element的人来说这个封装实在很简朴,但是对于我来说这个算是我这段练习期封装的比较好的一个组件了吧,固然除了封装这个组件另有别的事在做,不大概放着公司的活不干(哈哈哈哈︿( ̄︶ ̄)︿),总之在封装组件过程中学习到了不少东西,也算是一个大大的进步,于是来写一篇博客来纪录一下
到此这篇关于element el-table表格的二次封装实现(附表格高度自顺应)的文章就先容到这了,更多相关element el-table二次封装内容请搜刮脚本之家从前的文章或继续欣赏下面的相关文章盼望大家以后多多支持脚本之家!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

帖子地址: 

回复

使用道具 举报

分享
推广
火星云矿 | 预约S19Pro,享500抵1000!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

草根技术分享(草根吧)是全球知名中文IT技术交流平台,创建于2021年,包含原创博客、精品问答、职业培训、技术社区、资源下载等产品服务,提供原创、优质、完整内容的专业IT技术开发社区。
  • 官方手机版

  • 微信公众号

  • 商务合作