基于vue的el-table表格二次封装组件方法

前言

在公司实习使用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>
  • 表格の样子

  • 封装后

<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方法说明单元格要内嵌代码,就是用特殊列,反之就是正常列,所以formatterrender不能同时使用。

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有些地方使用方法不太一样。

  • 效果截图

结语

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

element el-table表格的vue组件二次封装(附表格高度自适应)的更多相关文章

  1. VUE组件 单独文件封装

    https://www.cnblogs.com/SamWeb/p/6391373.html vuejs 单文件组件.vue 文件   vuejs 自定义了一种.vue文件,可以把html, css, ...

  2. 7.vue组件(二)--双向绑定,父子组件访问

    本文主要说两件事 1. 如何实现父子组件之间的双向绑定 2. 父组件如何访问子组件的data,method, 子组件如何访问父组件的data,method等 一. 如何实现父子组件之间的双向绑定 案例 ...

  3. vue分页组件二次封装---每页请求特定数据

    关键步骤: 1.传两个参数:pageCount (每页条数).pageIndex (页码数): 2.bind方法的调用 <!-- 这部分是分页 --> <div class=&quo ...

  4. 13.vue组件

    vue组件(一) 组件嵌套: 1.全局嵌套: <!doctype html> <html> <head> <meta charset="utf-8& ...

  5. 封装Vue Element的table表格组件

    上周分享了几篇关于React组件封装方面的博文,这周就来分享几篇关于Vue组件封装方面的博文,也好让大家能更好地了解React和Vue在组件封装方面的区别. 在封装Vue组件时,我依旧会交叉使用函数式 ...

  6. vue+element ui 的表格列使用组件

    前言:工作中用到 vue+element ui 的前端框架,有这个场景:很多表格的列有许多一样的,所以考虑将列封装为组件.转载请注明出处:https://www.cnblogs.com/yuxiaol ...

  7. 应用五:Vue之ElementUI 表格Table与分页Pagination组件化

    (注:本文适用于有一定Vue基础或开发经验的读者,文章就知识点的讲解不一定全面,但却是开发过程中很实用的) 在平时的web项目开发过程中,列表分页查询展示应用的很频繁,为了便于阅读并减少代码的冗余,所 ...

  8. JS组件系列——又一款MVVM组件:Vue(二:构建自己的Vue组件)

    前言:转眼距离上篇 JS组件系列——又一款MVVM组件:Vue(一:30分钟搞定前端增删改查) 已有好几个月了,今天打算将它捡起来,发现好久不用,Vue相关技术点都生疏不少.经过这几个月的时间,Vue ...

  9. Vue+element ui table 导出到excel

    需求: Vue+element UI table下的根据搜索条件导出当前所有数据 参考: https://blog.csdn.net/u010427666/article/details/792081 ...

随机推荐

  1. IO 的五种模型是什么

    目录 前言 用户空间和内核空间 IO 五种模型 阻塞型 IO 非阻塞 IO IO 多路复用 信号驱动 IO 异步 IO 总结 阻塞和非阻塞 同步与异步 前言 我们经常看到阻塞/非阻塞,同步/异步这两组 ...

  2. 【UV统计】海量数据统计的前世今生

    转载请注明出处 背景 在互联网公司中,每个项目都需要数据统计.分析,便于项目组利用详细数据研究项目的整体情况,进行下一步的调整.在数据统计中,UV统计是最常见的,也是最普遍的.有的场景要求实时性很高, ...

  3. django添加检查用户名和手机号数量接口

    1.1 在user/urls.py中添加 urlpatterns = [ path('count/', views.RegCountView.as_view()), # 查询用户名手机号使用量的视图, ...

  4. 四、LoadRunner11安装和破解

    之前安装了LoadRunner12 社区版的,应为满足不了工作需求, 上网仔细查了教程下来LoadRunner11破解版 链接:https://pan.baidu.com/s/1dM8Lwf4p160 ...

  5. curl使用技巧汇总

    1,curl 忽略证书安全验证 curl https://192.168.1.5:8443-insecure -I

  6. Navicat Primium连接数据库报ORA-28547错误

    这个问题主要是Navicat Primium与orecal中的oci.dll版本不一致造成的,无论是本地数据库或者网络数据库. 解决方法:在数据库orecal安装目录中搜索oci.dll文件,找到后将 ...

  7. 牛客练习赛 73 D

    题目链接 离别 离线算法+线段树 容易发现当我们枚举右端点r时,符合条件的左端点是一段连续的区间 我们可以用队列来维护这个连续区间的左右端点 当枚举到端点\(i\)时,将下标\(i\)插入到队列\(q ...

  8. remmina 软件rdp协议链接windows失败

    remmina 1.42  链接 win10 提示失败......其他版本win还没有测试过. 忘记了在那个论坛有是说加密问题,照着改确实可以.具体原因是默认设置加密方式这一项不知道为什么不起作用,手 ...

  9. SimpleRev学习

    1.查壳 无壳,获取到信息64位,而且AMD x86-64 后面的信息平时没怎么关注,但是在这题里面有着关键指向作用 X86平台属于小端序,ARM平台属于大端序 涉及到字符串的储存问题 2.审题 题目 ...

  10. Application Data in Docker 笔记

    Application Data in Docker By default all files created inside a container are stored on a writable ...