基于element-ui进行二次封装的表格组件
<!--
* @description 表格组件
* @fileName TableList.vue
* @authorQ
* @date 2021/05/15 15:13:45
-->
<template>
<div class="table-container">
<el-table
v-if="showTable"
ref="filterTable"
:span-method="spanName?objectSpanMethod:null"
:data="data"
:show-summary="showSummary.show ? showSummary.show : null"
:summary-method="showSummary.show ? summaryMethod : null"
:sum-text="showSummary.sumText ? showSummary.sumText : null"
@filter-change="handleFilterChange"
:border="border"
:stripe="stripe"
empty-text="暂无数据"
style="width: 100%"
:show-header="showHeader"
:tooltip-effect="tooltipTheme"
@selection-change="handleSelectionChange"
>
<!-- 选择框列 -->
<el-table-column
v-if="selection"
type="selection"
:align="'center'"
></el-table-column>
<!-- 排序列 -->
<el-table-column
v-if="indexShow"
width="100"
label="序号"
:align="'center'"
>
<template slot-scope="scope">
<div>
<span>{{ scope.$index + 1 }}</span>
</div>
</template>
</el-table-column> <template v-for="(item, index) in columns">
<!-- 特殊列处理 -->
<template v-if="item.render">
<!-- visible 是否显示该列 -->
<el-table-column
v-if="item.visible"
:filters="item.filters ? item.filters : null"
:column-key="item.prop"
:key="index"
:prop="item.prop ? item.prop : null"
:align="item.align ? item.align : null"
:fixed="item.fixed ? item.fixed : null"
:label="item.label ? item.label : null"
:show-overflow-tooltip="item.tooltip"
:class-name="className"
:sortable="item.sortable ? item.sortable : false"
:width="item.width ? item.width : null"
>
<!-- 多级表头 -->
<template v-if="item.children && item.children.length > 0">
<div v-for="(item1, index1) in item.children" :key="index1">
<el-table-column
:key="index1"
:filters="item.filters ? item.filters : null"
:column-key="item.prop"
:prop="item1.prop ? item1.prop : null"
:align="item1.align ? item1.align : null"
:fixed="item1.fixed ? item1.fixed : null"
:label="item1.label ? item1.label : null"
:show-overflow-tooltip="item1.tooltip"
:class-name="className"
:sortable="item1.sortable ? item1.sortable : false"
:width="item1.width ? item1.width : null"
>
<exSlot
:render="item1.render"
:row="scope.row"
:index1="scope.$index"
:column="item1"
/>
</el-table-column>
</div>
</template>
<!-- 不是多级表头 -->
<template slot-scope="scope">
<exSlot
:render="item.render"
:row="scope.row"
:index="scope.$index"
:column="item"
/>
</template>
</el-table-column>
</template> <!-- 正常列 -->
<template v-else>
<!-- visible 是否显示该列 -->
<el-table-column
v-if="item.visible"
:key="index"
:column-key="item.prop"
:filters="item.filters ? item.filters : null"
:prop="item.prop ? item.prop : null"
:align="item.align ? item.align : null"
:fixed="item.fixed ? item.fixed : null"
:label="item.label ? item.label : null"
:class-name="className"
:show-overflow-tooltip="item.tooltip"
:sortable="item.sortable ? item.sortable : false"
:width="item.width ? item.width : null"
>
<!-- 多级表头 -->
<template v-if="item.children && item.children.length > 0">
<template v-for="(item1, index1) in item.children">
<el-table-column
:prop="item1.prop ? item1.prop : null"
:column-key="item.prop"
:filters="item.filters ? item.filters : null"
:align="item1.align ? item1.align : null"
:fixed="item1.fixed ? item1.fixed : null"
:label="item1.label ? item1.label : null"
:show-overflow-tooltip="item1.tooltip"
:class-name="className"
:sortable="item1.sortable ? item1.sortable : false"
:width="item1.width ? item1.width : null"
>
<template slot-scope="scope">
<span v-html="formatter(scope.row[item1.prop])"></span>
</template>
</el-table-column>
</template>
</template>
<template slot-scope="scope">
<!-- 字典处理 -->
<template v-if="item.dict">
<!-- 判断原始数据是否有效,有效转为字典数据,无效则转为--占位符 -->
<span
v-if="!scope.row[item.prop]"
v-html="formatter(scope.row[item.prop])"
></span>
<dict-tag
v-else
:options="dict.type[item.prop]"
:value="scope.row[item.prop]"
/>
</template>
<!-- 时间格式化 -->
<span v-else-if="item.time">{{
parseTime(scope.row[item.prop], "{y}-{m}-{d}")
}}</span>
<!-- 不做处理 -->
<span v-else v-html="formatter(scope.row[item.prop])"></span>
</template>
</el-table-column>
</template>
</template> <!-- 操作列 -->
<el-table-column
v-if="isEdit === true"
label="操作"
:align="'center'"
width="200"
:fixed="fixed"
>
<template slot-scope="scope">
<slot name="editSlot">
<template>
<el-button type="primary" @click="editClick(scope.row)"
>编辑</el-button
>
<el-button type="danger" @click="deleteClick(scope.row)"
>删除</el-button
>
</template>
</slot>
</template>
</el-table-column>
</el-table>
<el-pagination
:style="{ float: `${paginationPosition}` }"
v-if="pagination"
:background="background"
:current-page.sync="currentPage"
:page-size.sync="currentSize"
:layout="layout"
:page-sizes="pageSizes"
:total="total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</template> <script>
// 自定义内容的组件
var exSlot = {
functional: true,
props: {
row: Object,
render: Function,
index: Number,
column: {
type: Object,
default: null,
},
},
// render 函数
render: (h, context) => {
const params = {
row: context.props.row,
index: context.props.index,
};
if (context.props.columns) params.columns = context.props.columns;
return context.props.render(h, params);
},
};
export default {
name: "TableList",
components: { exSlot },
props: {
data: {
type: Array,
default: () => [],
},
update: {
type: Number,
default: () => null,
}, // 是否显示合计列
showSummary: {
type: Object,
default: () => {
return {
show: false,
sumText: "总计",
};
},
},
// 需要通过那个字段属性进行比较合并
spanName: {
type: String,
default: () => {
return null;
},
},
// 需要合并数组
spanColumnArr:{
type:Array,
default:()=>{
return [0]
}
},
tooltipTheme: {
type: String,
default: "dark",
},
// 是否显示表头
showHeader: {
type: Boolean,
default: true,
},
// 是否添加排序列
indexShow: {
type: Boolean,
default: true,
},
showTable: {
type: Boolean,
default: true,
},
// 是否显示选择框列
selection: {
type: Boolean,
default: false,
},
// 字段名
columns: {
type: Array,
default: () => [],
},
// 是否含有边框
border: {
type: Boolean,
default: false,
}, // 是否显示斑马条纹
stripe: {
type: Boolean,
default: false,
},
// 是否是可以编辑的表格
isEdit: {
type: Boolean,
default: false,
},
// 是否固定右侧一列,只对右侧操作栏起作用
fixed: {
type: String,
default: "right",
}, // 是否显示分页
pagination: {
type: Boolean,
default: false,
},
// 分页的位置
paginationPosition: {
type: String,
default: "center",
},
total: {
required: false,
type: Number,
},
page: {
type: Number,
default: 1, // 默认第一页
},
limit: {
type: Number,
default: 10, // 默认每页20条
},
pageSizes: {
type: Array,
// default: [10, 20, 30, 50]
default: function () {
return [1, 2, 3, 5]; // 默认显示可选的每页多少条数据
},
},
layout: {
type: String,
default: "total, sizes, prev, pager, next, jumper",
},
background: {
type: Boolean,
default: true,
},
autoScroll: {
type: Boolean,
default: true,
},
hidden: {
type: Boolean,
default: false,
},
className: {
type: String,
default: "",
},
render: {
type: Function,
default: function () {},
},
},
data() {
return {
cloneColumns: [],
spanArr: [], // 跨行数组
pos: null, // 跨行数组
};
},
computed: {
// 当前页多少条数据并且赋值给父组件
currentPage: {
get() {
return this.page;
},
set(val) {
this.$emit("update:page", val);
},
},
// 改变当前页几条数据得值赋值给父组件
currentSize: {
get() {
return this.limit;
},
set(val) {
this.$emit("update:limit", val);
},
},
},
created() {
this.cloneColumns = JSON.parse(JSON.stringify(this.columns));
},
watch: {
columns(value) {},
},
mounted() {
if (this.spanName) {
this.getSpanArr(this.data);
}
}, methods: {
// 合同单元格直接传入:spanName="id或者其他字段属性名"
getSpanArr(data) {
for (let i = 0; i < data.length; i++) {
if (i === 0) {
this.spanArr.push(1);
this.pos = 0;
} else {
// 判断当前的元素和上一个元素是否相同
// name 需要通过哪个字段来进行比较合并
if (data[i][this.spanName] === data[i - 1][this.spanName]) {
this.spanArr[this.pos] += 1;
this.spanArr.push(0);
} else {
this.spanArr.push(1);
this.pos = i;
}
}
}
}, // 合并
objectSpanMethod({ row, column, rowIndex, columnIndex }) {
if (this.spanColumnArr.includes(columnIndex)) {
const _row = this.spanArr[rowIndex];
const _col = _row > 0 ? 1 : 0;
return {
rowspan: _row,
colspan: _col,
};
}
}, // 自定义合计行
summaryMethod(params) {
const { columns, data } = params;
const sums = [];
columns.forEach((column, index) => {
if (index === 0) {
sums[index] = "总计";
return;
}
const values = data.map((item) => item[column.property]);
let num = 0;
for (let i = 0; i < values.length; i++) {
if (values[i]) {
num += Number(values[i]);
sums[index] = num;
} else {
if (isNaN(values[i])) {
} else {
num += Number(values[i]);
sums[index] = num;
}
}
}
if (column.property === "lv1Time" || column.property === "lv2Time") {
if (values.filter(Boolean).length === 0) {
sums[index] = "";
} else {
let num = 0;
for (let i = 0; i < values.length; i++) {
if (values[i]) {
num += Number(values[i]);
sums[index] = num;
} else {
if (isNaN(values[i])) {
} else {
num += Number(values[i]);
sums[index] = num;
}
}
}
}
}
});
let arr = [];
sums.map((i, index) => {
if (index === 0) {
arr.push(i);
} else {
if (!isNaN(i)) {
arr.push(i);
} else {
arr.push("");
}
}
});
return arr;
},
handleFilterChange(filters) {
if (filters.length > 0) {
this.$refs.filterTable.clearSelection();
this.$refs.filterTable.toggleRowSelection(filters.pop());
} else {
this.columns.map((item) => {
// 判断当前是那一列进行了筛选
if (item.prop === Object.keys(filters)[0]) {
item.filterValues = filters;
}
}); this.$emit("filtersParams", this.columns);
}
},
// 当前行当前列数据是否有效,无效的话,返回--占位符
formatter(row) {
if (row) {
return isNaN(parseFloat(row)) && isFinite(row)
? '<span class="isNaN">--</span>'
: row;
} else {
return '<span class="isNaN">--</span>';
}
},
/**
* @param {*}
* @return {*}
* @author: Q
* @Date: 2021-09-01 11:56:37
* @description: 已选的数据项
*/
handleSelectionChange(val) {
this.$emit("selectVal", val);
},
handleSizeChange(val) {
this.pageSize = val;
this.$emit("pagination", { pageIndex: this.page, pageSize: val });
},
handleCurrentChange(val) {
this.$emit("pagination", { pageIndex: val, pageSize: this.limit });
},
// 修改按钮的点击事件
editClick(val) {
this.$emit("edit", val);
},
// 删除按钮点击事件
deleteClick(val) {
this.$confirm("此操作将永久删除该文件, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
this.$emit("del", val);
})
.catch(() => {
this.$message({
type: "info",
message: "已取消删除",
});
});
},
},
};
</script> <style lang="scss">
.table-container {
text-align: center;
.el-pagination {
margin-left: 0 !important;
margin-top: 0 !important;
background: #fff !important;
height: 112px;
line-height: 112px;
display: flex;
justify-content: center;
align-items: center;
ul {
display: flex;
justify-content: space-around;
align-items: center;
li {
border-radius: 6px !important;
color: #666666 !important;
}
.active {
color: #fff !important;
background: #1677ffff !important;
}
}
button {
border-radius: 6px !important;
color: #666666 !important;
}
}
}
.table-container.el-table {
margin-top: 20px;
} .table-container .el-pagination {
margin-top: 20px;
margin-left: 20px;
}
.isNaN {
color: red;
}
</style>
基于element-ui进行二次封装的表格组件的更多相关文章
- 基于element UI 的上传插件
为了不再重复的上传文件,做了一个统一选择文件和上传文件的 基于 element UI :http://element-cn.eleme.io 前端实现文件下载和拖拽上传 演示 用法 <uploa ...
- python+selenium十:基于原生selenium的二次封装
from selenium import webdriverfrom selenium.webdriver.support.wait import WebDriverWaitfrom selenium ...
- 基于element ui的图片预览插件
写插件很简单,满足两个条件即可,一.基本的逻辑思路,二.熟悉插件语法要求.本次Vue插件也比较简单,点击“查看图片”用轮播的方式限制用户上传的图片,如图: 项目采用的是vue-element-admi ...
- element-ul二次封装table表格
在项目中el的表格使用的地方太多了,若不进行封装,使用的时候页面会显得非常的冗余且难以维护,有时表格样式还不能做到一致:今天分享一个在工作中封装的表格 由于大多代码都在页面有介绍,就不在外面解释了 一 ...
- 基于element ui的级联选择器组件实现的分类后台接口
今天在做资产管理系统的时候遇到一个分类的级联选择器,前端是用的element的组件,需要后台提供接口支持. 这个组件需要传入的数据结构大概是这样的,详细的可参考官方案例: [{ value: ...
- 【原创】基于Bootstrap的Modal二次封装
前言 Bootstrap:Twitter推出的一个开源的用于前端开发的工具包.它由Twitter的设计师Mark Otto和Jacob Thornton合作开发,是一个CSS/HTML框架 官方网站: ...
- vue基于 element ui 的按钮点击节流
vue的按钮点击节流 场景: 1.在实际使用中,当我们填写表单,点击按钮提交的时候,当接口没返回之前,迅速的点击几次,就会造成多次提交. 2.获取验证码,不频繁的获取. 3.弹幕不能频繁的发 基于这几 ...
- 基于element ui 实现七牛云自定义key上传文件,并监听更新上传进度
借助上传Upload 上传组件的 http-request 覆盖默认的上传行为,可以自定义上传的实现 <el-upload multiple ref="sliderUpload&quo ...
- 手把手教学~基于element封装tree树状下拉框
在日常项目开发中,树状下拉框的需求还是比较常见的,但是element并没有这种组件以供使用.在这里,小编就基于element如何封装一个树状下拉框做个详细的介绍. 通过这篇文章,你可以了解学习到一个树 ...
- python+selenium十:selenium的二次封装
python+selenium十:基于原生selenium的二次封装 from selenium import webdriverfrom selenium.webdriver.support.w ...
随机推荐
- iOS开发之运行报错 dyld: Library not loaded: *** Reason: image not found
xcode运行报错 dyld: Library not loaded: @rpath/Flutter.framework/Flutter Referenced from: /private/var ...
- VMware 15pro虚拟机网络设置
在关闭虚拟机的情况下:VM 15pro. 编辑->虚拟网络编辑器:
- js-模态框的拖动
效果如下: 代码如下: <div class="clickBtn">点击,弹出登录框</div> <div class="login&quo ...
- 异步Udp监听关闭 出现异常,访问已释放的资源或者其他错误的解决方法
在开发异步Udp程序的过程中,通常在关闭UDP的时候回遇到诸如socket 访问已释放的资源之类的异常,如下简单操作下: 1 Udp的监听 2 this.serverSocket = new Sock ...
- maven安装在idea中报错
java.lang.RuntimeException: java.lang.RuntimeException: org.codehaus.plexus.component.repository.exc ...
- 求两个自然数之间的最大公约数C++实现
1 #include "pch.h" 2 #include <iostream> 3 using namespace std; 4 5 int main() 6 { 7 ...
- C语言ll一作业01
1. 作业头 | 这个作业属于哪个课程 | https://edu.cnblogs.com/campus/zswxy/SE2020-3 | | ---- | ---- | ---- | | 这个作业目 ...
- 学校——DFS图的遍历
学校实验 没什么多说的 就是实现一个图的遍历 由于学校已经输入的片段过于晦涩难懂 无法进行 在网上看了别人写的代码 提升了理解代码的一点能力 #include"string.h" ...
- 安卓蓝牙协议栈中的RFCOMM状态机分析
1.1 数据结构 1.1.1 tRFC_MCB tRFC_MCB(type of rfcomm multiplexor control block的简写)代表了一个多路复用器.代表了RFCOMM规范 ...
- 【APT】响尾蛇(SideWinder)APT组织样本分析
基础信息 名称:NDC Participants.docx类型:.docMD5:df020e81b7ca32868a8ac1f5eddd086f描述:通过远程模板注入技术加载含有CVE-2017-11 ...