element el-table表格的vue组件二次封装(附表格高度自适应)
基于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
方法说明单元格要内嵌代码,就是用特殊列,反之就是正常列,所以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有些地方使用方法不太一样。
- 效果截图
结语
这次封装vue组件,花了我将近半个月的时间,从刚开始的接触到发现bug然后去修改,来来回回终于精简封装出现在这个二次封装的组件,可能对于熟悉vue和element的人来说这个封装其实很简单,但是对于我来说这个算是我这段实习期封装的比较好的一个组件了吧,当然除了封装这个组件还有别的事在做,不可能放着公司的活不干(哈哈哈哈︿( ̄︶ ̄)︿),总之在封装组件过程中学习到了不少东西,也算是一个大大的进步,于是来写一篇博客来记录一下。
element el-table表格的vue组件二次封装(附表格高度自适应)的更多相关文章
- VUE组件 单独文件封装
https://www.cnblogs.com/SamWeb/p/6391373.html vuejs 单文件组件.vue 文件 vuejs 自定义了一种.vue文件,可以把html, css, ...
- 7.vue组件(二)--双向绑定,父子组件访问
本文主要说两件事 1. 如何实现父子组件之间的双向绑定 2. 父组件如何访问子组件的data,method, 子组件如何访问父组件的data,method等 一. 如何实现父子组件之间的双向绑定 案例 ...
- vue分页组件二次封装---每页请求特定数据
关键步骤: 1.传两个参数:pageCount (每页条数).pageIndex (页码数): 2.bind方法的调用 <!-- 这部分是分页 --> <div class=&quo ...
- 13.vue组件
vue组件(一) 组件嵌套: 1.全局嵌套: <!doctype html> <html> <head> <meta charset="utf-8& ...
- 封装Vue Element的table表格组件
上周分享了几篇关于React组件封装方面的博文,这周就来分享几篇关于Vue组件封装方面的博文,也好让大家能更好地了解React和Vue在组件封装方面的区别. 在封装Vue组件时,我依旧会交叉使用函数式 ...
- vue+element ui 的表格列使用组件
前言:工作中用到 vue+element ui 的前端框架,有这个场景:很多表格的列有许多一样的,所以考虑将列封装为组件.转载请注明出处:https://www.cnblogs.com/yuxiaol ...
- 应用五:Vue之ElementUI 表格Table与分页Pagination组件化
(注:本文适用于有一定Vue基础或开发经验的读者,文章就知识点的讲解不一定全面,但却是开发过程中很实用的) 在平时的web项目开发过程中,列表分页查询展示应用的很频繁,为了便于阅读并减少代码的冗余,所 ...
- JS组件系列——又一款MVVM组件:Vue(二:构建自己的Vue组件)
前言:转眼距离上篇 JS组件系列——又一款MVVM组件:Vue(一:30分钟搞定前端增删改查) 已有好几个月了,今天打算将它捡起来,发现好久不用,Vue相关技术点都生疏不少.经过这几个月的时间,Vue ...
- Vue+element ui table 导出到excel
需求: Vue+element UI table下的根据搜索条件导出当前所有数据 参考: https://blog.csdn.net/u010427666/article/details/792081 ...
随机推荐
- jvm基本结构和解析
jvm的基本结构图如下 这只是代表我的个人理解 不是很深刻 欢迎各类大神进行补充和纠正 jvm之所以强大就是因为他从软件层面屏蔽不用操作系统在底层硬件与指令上的区别,从而可以在不同系统上兼容 主要 ...
- hive中的虚拟列
hive为用户提供了三个虚拟列:用户可以通过这三个虚拟列确定记录是来自哪个文件以及这条记录的具体位置信息 INPUT__FILE__NAME 返回记录所在的具体hdfs文件全路径 hive> s ...
- html 02-浏览器的介绍
02-浏览器的介绍 #常见的浏览器 浏览器是网页运行的平台,常见的浏览器有谷歌(Chrome).Safari.火狐(Firefox).IE.Edge.Opera等.如下图所示: 我们重点需要学习的是 ...
- Azure Service Bus(二)在NET Core 控制台中如何操作 Service Bus Queue
一,引言 上一篇讲到关于 Azure ServiceBus 的一些概念,讲到 Azure Service Bus(服务总线),其实也叫 "云消息服务",是微软在Azure 上提供的 ...
- Python循环语句代码详解:while、for、break
1 while循环 循环语句是程序设计中常用的语句之一.任何编程语言都有while循环,Python也不例外.while循环的格式如下所示. while(表达式): - else: ...
- Blogs添加横幅滚动条
#1.定义CSS样式 .box { width: 100%; margin: 0 auto; /* border: 0.2px solid gray; */ overflow: hidden; } . ...
- Spring Boot 中使用 Quartz 实现任务调度
Quartz 概述 Quartz 是 OpenSymphony 开源组织在 Job Scheduling 领域又一个开源项目,它可以与 J2EE. J2SE 应用程序相结合也可以单独使用.Quartz ...
- Linux(Centos7)安装、使用 Docker
一.Linux(CentOS7) 上安装 docker 1.docker 是什么? docker 是一种 虚拟化容器技术,一个开源的应用容器引擎. 基于镜像,可以秒级启动各种容器(运行一次镜像就生成一 ...
- 容器编排系统K8s之ConfigMap、Secret资源
前文我们了解了k8s上的pv/pvc/sc资源的使用和相关说明,回顾请参考:https://www.cnblogs.com/qiuhom-1874/p/14188621.html:今天我们主要来聊一下 ...
- js对flv提取h264、aac音视频流
FLV提取里面的h264视频流 FLV和MP4支持的编码 流媒体和媒体文件的区别 流媒体是指将一连串的多媒体资料压缩后,经过互联网分段发送资料,在互联网上即时传输影音以供观赏的一种技术与过程,此技术使 ...