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


Posted in Javascript onJanuary 19, 2021

前言

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

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

这里直接引用官方的基础使用模板,直接抄过来(✪ω✪),下面代码中主要是抽离html部分,可以看出每个el-table-column中都含有prop、label、width属性,只不过这些属性值不太一样罢了,其余的部分都差不多一样,所以表头(表格每列el-table-column的定义)这里可以封装一下,把不同的地方封装成一个数组对象结构,然后通过for循环来完成html中的部分。

封装前

<template>
  <el-table
   :data="tableData"
   style="width: 100%">
   <el-table-column
    prop="date"
    label="日期"
    width="180">
   </el-table-column>
   <el-table-column
    prop="name"
    label="姓名"
    width="180">
   </el-table-column>
   <el-table-column
    prop="address"
    label="地址">
   </el-table-column>
  </el-table>
 </template>

 <script>
  export default {
   data() {
    return {
     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 弄'
     }]
    }
   }
  }
 </script>

表格の样子

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

封装后

<template>
 <el-table :data="tableData" style="width: 100%">
  <template v-for="(item, key) in header">
   <el-table-column
    :key="key"
    :prop="itm.prop ? itm.prop : null"
    :label="itm.label ? itm.label : null"
    :width="itm.width ? itm.width : null"
   >
   </el-table-column>
  </template>
 </el-table>
</template>

<script>
export default {
 data() {
  return {
   header: [
    { prop: "date", label: "日期", width: "180" },
    { prop: "name", label: "姓名", width: "180" },
    { prop: "address", label: "地址" }
   ],
   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 弄"
    }
   ]
  };
 }
};
</script>

现在数据还比较少,可能看不出封装组件封装的优势,但是相对于之前代码,这里逻辑上看起来更加清晰,而且修改列的时候直接改动data中的header数据即可,不用再去html代码中去“开刀”( ̄? ̄)/。上面是最最最简单的封装了,严格来说只是简单的抽离了一下代码中的数据结构,在正常的业务中肯定不止这么简单的封装,接下来才是重点─━ _ ─━✧

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

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

el-table真正の二次封装

二次封装源代码

<template>
 <el-table
  empty-text="暂无数据"
  ref="table"
  :data="tableList"
  border
  stripe
  fit
  highlight-current-row
  :height="inTableHeight"
  @selection-change="selectionChange"
  @row-click="rowClick"
 >
  <!-- 选择框 -->
  <el-table-column
   v-if="select"
   type="selection"
   fixed="left"
   width="55"
   align="center"
  />
  <template v-for="(itm, idx) in header">
   <!-- 特殊处理列 -->
   <el-table-column
    v-if="itm.render"
    :key="idx"
    :prop="itm.prop ? itm.prop : null"
    :label="itm.label ? itm.label : null"
    :width="itm.width ? itm.width : null"
    :sortable="itm.sortable ? itm.sortable : false"
    :align="itm.align ? itm.align : 'center'"
    :fixed="itm.fixed ? itm.fixed : null"
    :show-overflow-tooltip="itm.tooltip"
    min-width="50"
   >
    <template slot-scope="scope">
     <ex-slot
      :render="itm.render"
      :row="scope.row"
      :index="scope.$index"
      :column="itm"
     />
    </template>
   </el-table-column>
   <!-- 正常列 -->
   <el-table-column
    v-else
    :key="idx"
    :prop="itm.prop ? itm.prop : null"
    :label="itm.label ? itm.label : null"
    :width="itm.width ? itm.width : null"
    :sortable="itm.sortable ? itm.sortable : false"
    :align="itm.align ? itm.align : 'center'"
    :fixed="itm.fixed ? itm.fixed : null"
    :formatter="itm.formatter"
    :show-overflow-tooltip="itm.tooltip"
    min-width="50"
   />
  </template>
 </el-table>
</template>

<script>
// 自定义内容的组件
var exSlot = {
 functional: true,
 props: {
  row: Object,
  render: Function,
  index: Number,
  column: {
   type: Object,
   default: null
  }
 },
 render: (h, context) => {
  const params = {
   row: context.props.row,
   index: context.props.index
  };
  if (context.props.column) params.column = context.props.column;
  return context.props.render(h, params);
 }
};

export default {
 components: { exSlot },
 props: {
  tableList: {
   type: Array,
   default: () => []
  },
  header: {
   type: Array,
   default: () => []
  },
  select: {
   type: Boolean,
   default: () => false
  },
  height: {
   type: [Number, String, Function],
   default: () => null
  }
 },
 data() {
  return {
   inTableHeight: null
  };
 },
 created() {
  //该阶段可以接收父组件的传递参数
  this.inTableHeight = this.height;
 },
 mounted() {
  this.$nextTick(() => {
   //表格高度自适应浏览器大小
   this.changeTableHight();
   if (!this.height) {
    window.onresize = () => {
     this.changeTableHight();
    };
   }
  });
 },
 destroyed() {
  //高度自适应事件注销
  window.onresize = null;
 },
 watch: {
  /**
   * 数据变化后 高度自适应
   */
  tableList() {
   this.$nextTick(() => {
    this.changeTableHight();
   });
  }
 },
 methods: {
  /**
   * 选择框选择后更改,事件分发
   */
  selectionChange(selection) {
   this.$emit("selection-change", selection);
  },
  /**
   * 点击事件
   */
  rowClick(row, column, event) {
   this.$emit("row-click", row, column, event);
  },
  /**
   * 高度自适应
   * 当表格展示空间小于460按460px展示,大于的时候高度填充
   */
  changeTableHight() {
   if (this.height) {
    //如果有传进来高度就取消自适应
    this.inTableHeight = this.height;
    this.$refs.table.doLayout();
    return;
   }
   let tableHeight = window.innerHeight || document.body.clientHeight;
   //高度设置
   let disTop = this.$refs.table.$el;
   //如果表格上方有元素则减去这些高度适应窗口,66是底下留白部分
   tableHeight -= disTop.offsetTop + 66;
   if (disTop.offsetParent) tableHeight -= disTop.offsetParent.offsetTop;
   this.inTableHeight = tableHeight < 460 ? 460 : tableHeight;
   //重绘表格
   this.$refs.table.doLayout();
  }
 }
};
</script>
<style></style>

封装代码的相关解释

以上就是我封装的代码,部分属性或者方法由于没有使用到所以我就没有将对应的方法和属性封装进去,如果你们开发中有用到对应的地方其实可以照猫画虎的填上去即可,我封装表格的时候在属性这里使用了三目运算符,用于做一些兼容,如果不传对应的属性就给个默认值,比如align属性,我设置的是默认居中。还有就是方法,在表格的方法引用方面,其实就是把官方的方法用$emit事件将对应的参数和方法名用同样的方法分发给父组件,这样父组件使用完全可以参照element官方文档使用这些方法,在组件内我只是进行了一次转发而已,我自己写的时候并没有用到太多的方法,所以只封装了一两个,如果有需要可以自行添加。除了上述两个封装,有一个特别的地方就是勾选框,不能放在循环内,不然会出现错误,可能是索引的问题吧,所以我单独使用一个参数来控制是否显示选择框。另外就是,在公司产品要求表格能够自适应页面的高度,这个功能我也是修改了好久,460是最小的高度,关于高度自适应的全部在changeTableHight()方法中,如果不需要这个功能,将函数和所有引用该函数的地方删除即可。

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

render:终于到了最关键的地方了( ̄? ̄)/,这个可是我封装表格的最大难点了,render对我个人理解而言就是虚拟结点,在DOM和CSSOM树合并为render树的阶段,对代码进行修改。

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

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

封装这么久的组件,当然要使用起来才知道的到底好不好用,关于引用方面,首先要在引用的地方进行组件注册,如果全局注册过了,可以忽略在局部注册,关于组件的注册这里就不做详解了(o゚?゚)o  。我使用了全局注册,所以这里是直接引入我自己封装好的组件。

<template>
 <div class="hello">
  <xd-table :table-list="tableData" :header="header" height="300"></xd-table>
 </div>
</template>

<script>
export default {
 name: "HelloWorld",
 data() {
  return {
   header: [
    { prop: "w", label: "w" },
    { prop: "x", label: "x",
     formatter: (row) => {
      return row.x.toFixed(3);
     },
    },
    { prop: "d", label: "d",
     formatter: (row) => {
      return row.d.toFixed(2);
     },
    },
    {
     label: "操作",
     render: (h, data) => {
      return (
       <el-button
        type="primary"
        onClick={() => {
         this.handleClick(data.row);
        }}
       >
        点我获取行数据
       </el-button>
      );
     },
    },
   ],
   tableData: [
    { w: 1, x: 99.25123, d: 0.23892 },
    { w: 1, x: 255.6666, d: 0.99134 },
   ],
  };
 },
 methods: {
  handleClick(row) {
   console.log(row);
  },
 },
};
</script>

引用组件之前一定要记得先注册,这里我只使用了几个属性,其他属性没有使用,因为是demo,主要还是展示render内嵌代码的方法,还有一个就是官方formatter方法的使用。
有一个需要注意点就是render内我使用了JSX模板语法这里需要在VUE项目中单独去配置一下JSX语法,如果不想使用JSX,直接写也可以,因为不使用JSX语法写出来的内嵌模板代码比较难读所以我就不展示了,个人建议还是使用JSX语法,虽然和原生vue有些地方使用方法不太一样。

效果截图

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

结语

这次封装vue组件,花了我将近半个月的时间,从刚开始的接触到发现bug然后去修改,来来回回终于精简封装出现在这个二次封装的组件,可能对于熟悉vue和element的人来说这个封装其实很简单,但是对于我来说这个算是我这段实习期封装的比较好的一个组件了吧,当然除了封装这个组件还有别的事在做,不可能放着公司的活不干(哈哈哈哈︿( ̄︶ ̄)︿),总之在封装组件过程中学习到了不少东西,也算是一个大大的进步,于是来写一篇博客来记录一下

到此这篇关于element el-table表格的二次封装实现(附表格高度自适应)的文章就介绍到这了,更多相关element el-table二次封装内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木! 

Javascript 相关文章推荐
动态改变textbox的宽高的js
Oct 26 Javascript
JavaScript的9个陷阱及评点分析
May 16 Javascript
js选项卡的实现方法
Feb 09 Javascript
JavaScript中用于生成随机数的Math.random()方法
Jun 15 Javascript
javascript实现table单元格点击展开隐藏效果(实例代码)
Apr 10 Javascript
微信小程序访问node.js接口服务器搭建教程
Apr 25 Javascript
详解node中创建服务进程
May 09 Javascript
JS设计模式之数据访问对象模式的实例讲解
Sep 30 Javascript
关于vue v-for 循环问题(一行显示四个,每一行的最右边那个计算属性)
Sep 04 Javascript
js的新生代垃圾回收知识点总结
Aug 22 Javascript
微信公众号网页分享功能开发的示例代码
May 27 Javascript
vue使用echarts实现水平柱形图实例
Sep 09 Javascript
JS实现纸牌发牌动画
Jan 19 #Javascript
微信小程序canvas实现签名功能
Jan 19 #Javascript
vue二选一tab栏切换新做法实现
Jan 19 #Vue.js
微信小程序选择图片控件
Jan 19 #Javascript
jQuery冲突问题解决方法
Jan 19 #jQuery
js实现随机点名
Jan 19 #Javascript
js实现有趣的倒计时效果
Jan 19 #Javascript
You might like
《PHP编程最快明白》第五讲:php目录、文件操作
2010/11/01 PHP
超级实用的7个PHP代码片段分享
2012/01/05 PHP
关于PHP模板Smarty的初级使用方法以及心得分享
2013/06/21 PHP
php中替换字符串中的空格为逗号','的方法
2014/06/09 PHP
可以保证单词完整性的PHP英文字符串截取代码分享
2014/07/15 PHP
php实现删除指定目录下相关文件的方法
2014/10/20 PHP
PHP+Ajax实现的无刷新分页功能详解【附demo源码下载】
2017/07/03 PHP
如何快速的呈现我们的网页的技巧整理
2007/07/01 Javascript
JSON 编辑器实现代码
2009/12/06 Javascript
基于mootools插件实现遮罩层新手引导
2012/05/24 Javascript
JavaScript禁止页面操作的示例代码
2013/12/17 Javascript
JS实现的N多简单无缝滚动代码(包含图文效果)
2015/11/06 Javascript
原生js模拟淘宝购物车项目实战
2015/11/18 Javascript
深入理解Ajax的get和post请求
2016/06/02 Javascript
Javascript字符串常用方法详解
2016/07/21 Javascript
利用vue-router实现二级菜单内容转换
2016/11/30 Javascript
使用cookie绕过验证码登录的实现代码
2017/10/12 Javascript
微信小程序利用canvas 绘制幸运大转盘功能
2018/07/06 Javascript
JavaScript Date对象功能与用法学习记录
2020/04/28 Javascript
工作中常用js功能汇总
2020/11/07 Javascript
vue iview 隐藏Table组件里的某一列操作
2020/11/13 Javascript
Python 私有化操作实例分析
2019/11/21 Python
python 如何实现遗传算法
2020/09/22 Python
使用gunicorn部署django项目的问题
2020/12/30 Python
乐高瑞士官方商店:LEGO CH
2020/08/16 全球购物
这段代码难道不该打印出56吗
2013/02/27 面试题
保密普查工作实施方案
2014/02/25 职场文书
弘扬职业精神演讲稿
2014/03/20 职场文书
幼儿园小班教师寄语
2014/04/03 职场文书
《明天,我们毕业》教学反思
2014/04/24 职场文书
2014年师德承诺书
2014/05/23 职场文书
涉密人员保密承诺书
2014/05/28 职场文书
2015大学生暑假调查报告
2015/07/13 职场文书
运动会广播稿200字
2015/08/19 职场文书
2016年九九重阳节活动总结
2016/04/01 职场文书
Lombok的详细使用及优缺点总结
2021/07/15 Java/Android