📝 个人简介
⭐ 个人主页:我是段段🙋
🍊 博客领域:编程基础、前端💻
🍅 写作风格:干货!干货!都是干货!
🍑 精选专栏:Vue
🛸 支持段段:点赞👍、收藏⭐、留言💬
前言
在项目中编写数据大屏的时候,除了柱状图、折线图、散点图…,还有表格展示
,首先想到的是Element
的el-table
表格,但是在后续的实现过程中,后端范围的列数是动态的,刚开始没有考虑到el-table的slot
,然后采用了第一种方式,但是数据处理方式不太好,后来在Element官网查看了文档,就使用solt
方式进行实现(第二种方式),不过两种方式都需要对数据进行处理
第一种方式
第一种方式主要使用v-for
循环实现,页面逻辑比较简单,具体布局如下:
<template>
<div class="echarts-table">
<!-- 用来渲染表格头部 -->
<div class="table-title">
<div
v-for="(item, index) in colsArr"
:key="index"
:style="initStyle()"
:title="item"
>
<span>{{ item }}</span>
</div>
</div>
<!-- 此处for循环用来渲染行数 -->
<div
v-for="(item, index) in initDataList"
:key="index"
class="table-content"
:class="{ 'odd-number': index % 2 != 0 }"
>
<!-- 此处for循环用来渲染列数 -->
<div
v-for="(prop, idx) in item"
:key="idx"
:style="initStyle()"
:title="idx != 0 ? prop : ''"
>
<div v-if="idx == 0">
<span class="icon">{{ prop }}</span>
</div>
<span v-else>{{ prop }}</span>
</div>
</div>
</div>
</template>
data
中数据如下:
data() {
return {
// 表头 单独存放一个数组
colsArr: ['排名', '区域', '集备主题', '评论次数', '参与教师数'],
// 数据 需要将数据处理成此种形式 dataList中的每一个子项即是一行数据
dataList: [
['xxx区域区域', '春/朱自清', '1', '5'],
['xxx区域', '济南的冬天/老舍', '8', '24'],
['xxx区域', '大榕树', '2', '18'],
['xxx区域', '你猜', '20', '18'],
['xxx区域', '大榕树', '12', '18'],
]
};
}
使用计算属性
来处理数据,将数据处理成渲染需要的格式,如下:
computed: {
// 在数据的第一列是排名,项目中使用的是图片,且不是后端返回的,需要对每一行的数据进行处理
initDataList() {
this.dataList.forEach( (item, index) => {
item.unshift(index + 1);
})
return this.dataList;
}
}
因为列数不固定,需要每一列的宽度也需要动态的计算,通过动态style
来实现,具体如下:
/*
* 通过表头的长度来动态计算每一个列的宽度,此种方式在小程序端不可使用
*/
initStyle() {
return {
width: `calc(100% / ${this.colsArr.length})`,
margin: '0 0.4%',
overflow: 'hidden',
whiteSpace: 'nowrap',
textOverflow: 'ellipsis'
}
}
实现效果图如下:
完整代码附上:
<template>
<div class="echarts-table">
<!-- 用来渲染表格头部 -->
<div class="table-title">
<div
v-for="(item, index) in colsArr"
:key="index"
:style="initStyle()"
:title="item"
>
<span>{{ item }}</span>
</div>
</div>
<!-- 此处for循环用来渲染行数 -->
<div
v-for="(item, index) in initDataList"
:key="index"
class="table-content"
:class="{ 'odd-number': index % 2 != 0 }"
>
<!-- 此处for循环用来渲染列数 -->
<div
v-for="(prop, idx) in item"
:key="idx"
:style="initStyle()"
:title="idx != 0 ? prop : ''"
>
<div v-if="idx == 0">
<span class="icon">{{ prop }}</span>
</div>
<span v-else>{{ prop }}</span>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
// 表头 单独存放一个数组
colsArr: ['排名', '区域', '集备主题', '评论次数', '参与教师数'],
// 数据 需要将数据处理成此种形式 dataList中的每一个子项即是一行数据
dataList: [
['xxx区域区域', '春/朱自清', '1', '5'],
['xxx区域', '济南的冬天/老舍', '8', '24'],
['xxx区域', '大榕树', '2', '18'],
['xxx区域', '你猜', '20', '18'],
['xxx区域', '大榕树', '12', '18'],
]
};
},
computed: {
// 在数据的第一列是排名,项目中使用的是图片,且不是后端返回的,需要对每一行的数据进行处理
initDataList() {
this.dataList.forEach( (item, index) => {
item.unshift(index + 1);
})
return this.dataList;
}
},
methods: {
/*
* 通过表头的长度来动态计算每一个列的宽度,此种方式在小程序端不可使用
*/
initStyle() {
return {
width: `calc(100% / ${this.colsArr.length})`,
margin: '0 0.4%',
overflow: 'hidden',
whiteSpace: 'nowrap',
textOverflow: 'ellipsis'
}
}
}
};
</script>
<style lang="stylus" scoped>
.echarts-table
color #FFF
cursor default
.table-title
width 100%
height 40px
font-size 14px
background #212949
display flex
align-items center
text-align center
.table-content
width 100%
height 40px
font-size 14px
display flex
align-items center
text-align center
img
height 20px
vertical-align middle
span.icon
display inline-block
width 20px
height 20px
line-height 20px
text-align center
border 1px solid #FFFFFF
border-radius 50%
.odd-number
background #212949
</style>
第二种方式
第二种方式主要使用了Element的slot
属性,也需要把数据处理成渲染需要的格式,相对来说比第一种方式稍复杂,页面布局如下:
<template>
<div class="element-table">
<el-table
:data="initDataList"
style="width: 100%"
:header-cell-style="{ background: '#212949' }"
>
<el-table-column
v-for="(item, index) in colsArr"
:key="index"
:label="item.colName"
align="center"
:show-overflow-tooltip="true"
min-width="60"
>
<template slot-scope="scope">
<div v-if="index == 0">
<span class="icon">{{ scope.row[item.key].value }}</span>
</div>
<span v-else>{{ scope.row[item.key].value }}</span>
</template>
</el-table-column>
</el-table>
</div>
</template>
data
中的数据如下:
data() {
return {
/**
* @params
* colName 表头名称
* key 自定义列名 处理数据是使用
*/
colsArr: [
{ colName: '排名', key: 'cols0' },
{ colName: '区域', key: 'cols1' },
{ colName: '主题名称', key: 'cols2' },
{ colName: '次数', key: 'cols3' },
{ colName: '人数', key: 'cols4' }
],
/**
* @params
* 此处的列名必须和colsArr中定义的一致
*/
dataList: [
{ cols1: '区域1', cols2: '春', cols3: 1, cols4: 5 },
{ cols1: '区域2', cols2: '春', cols3: 8, cols4: 24 },
{ cols1: '区域3', cols2: '春', cols3: 18, cols4: 52 },
{ cols1: '区域4', cols2: '春', cols3: 1, cols4: 35 },
{ cols1: '区域5', cols2: '春', cols3: 1, cols4: 20 }
]
};
}
也需要计算属性
来处理数据:如下:
computed: {
// 处理数据
initDataList() {
let arr = [];
this.dataList.forEach((item, index) => {
let obj = {};
this.colsArr.forEach((prop, idx) => {
if(idx == 0) {
obj[prop.key] = { value: index + 1, name: prop.colName };
} else {
obj[prop.key] = { value: item[prop.key], name: prop.colName };
}
})
arr.push(obj);
})
return arr;
}
}
实现效果图如下:
完整代码附上:
<template>
<div class="element-table">
<el-table
:data="initDataList"
style="width: 100%"
:header-cell-style="{ background: '#212949' }"
>
<el-table-column
v-for="(item, index) in colsArr"
:key="index"
:label="item.colName"
align="center"
:show-overflow-tooltip="true"
min-width="60"
>
<template slot-scope="scope">
<div v-if="index == 0">
<span class="icon">{{ scope.row[item.key].value }}</span>
</div>
<span v-else>{{ scope.row[item.key].value }}</span>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
export default {
data() {
return {
/**
* @params
* colName 表头名称
* key 自定义列名 处理数据是使用
*/
colsArr: [
{ colName: '排名', key: 'cols0' },
{ colName: '区域', key: 'cols1' },
{ colName: '主题名称', key: 'cols2' },
{ colName: '次数', key: 'cols3' },
{ colName: '人数', key: 'cols4' }
],
/**
* @params
* 此处的列名必须和colsArr中定义的一致
*/
dataList: [
{ cols1: '区域1', cols2: '春', cols3: 1, cols4: 5 },
{ cols1: '区域2', cols2: '春', cols3: 8, cols4: 24 },
{ cols1: '区域3', cols2: '春', cols3: 18, cols4: 52 },
{ cols1: '区域4', cols2: '春', cols3: 1, cols4: 35 },
{ cols1: '区域5', cols2: '春', cols3: 1, cols4: 20 }
]
};
},
computed: {
// 处理数据
initDataList() {
let arr = [];
this.dataList.forEach((item, index) => {
let obj = {};
this.colsArr.forEach((prop, idx) => {
if(idx == 0) {
obj[prop.key] = { value: index + 1, name: prop.colName };
} else {
obj[prop.key] = { value: item[prop.key], name: prop.colName };
}
})
arr.push(obj);
})
return arr;
}
}
};
</script>
<style lang="stylus" scoped>
.element-table {
/deep/ .el-table {
background-color: rgba(0, 0, 0, 0);
}
/deep/ .el-table::before {
height: 0;
}
/deep/ .el-table th.el-table__cell,
/deep/ .el-table td.el-table__cell {
border-bottom: none;
padding: 0;
color: #FFF;
font-size: 14px;
}
/deep/ .el-table .el-table__header-wrapper {
height: 40px;
line-height: 40px;
}
/deep/ .el-table .el-table__header-wrapper .cell {
white-space: nowrap;
text-overflow: ellipsis;
}
/deep/ .el-table .el-table__row {
height: 40px;
background: #182041;
img {
height: 20px;
vertical-align: middle;
}
&:nth-child(2),
&:nth-child(4) {
background: #212949;
}
}
/deep/ .el-table tbody tr:hover > td {
background: rgba(0, 0, 0, 0);
}
/deep/ .el-table__empty-block {
background: #182041;
}
span.icon {
display: inline-block;
width: 20px;
height: 20px;
line-height: 20px;
text-align: center;
border: 1px solid #FFFFFF;
border-radius: 2px;
}
}
</style>
总之,两种方式的渲染结果没有明显的差异,具体使用那种方式需要根据业务需求决定
好长时间没更新了,最近太忙了呀⏳~
分割线~~~
来补更一个吧~,在项目中用到了sortable
属性进行排序,以上两种方式都存在问题
第三种方式
也是使用了Element的slot属性,需要把数据处理成渲染需要的格式,处理起来相对简单
将表格封装成了组件NewsTable.vue
,页面布局如下:
<template>
<div class="news-table">
<el-table
:max-height="config.max_height"
:data="config.table_data"
style="width: 100%"
:header-cell-style="{ background: '#212949' }"
>
<el-table-column
align="center"
v-for="(item, index, key) in config.table_cols"
:key="key"
:index="index"
:label="item.label"
:prop="item.prop"
:width="item.width"
:fixed="item.fixed"
:show-overflow-tooltip="true"
:sortable="item.sort"
>
<template slot-scope="scope">
<span>{{ scope.row[item.prop] }}</span>
</template>
</el-table-column>
</el-table>
</div>
</template>
在需要用到表格的地方引入即可
import NewTable from '../components/Common/NewsTable.vue';
然后在页面使用
<NewTable :config="tableConfig"></NewTable>
tableConfig中的数据如下
tableConfig: {
max_height: 240,
table_cols: [
{ prop: 'rank', label: '排名', width: '', fixed: false, sort: false },
{ prop: 'area', label: '区域', width: '', fixed: false, sort: false },
{ prop: 'theme', label: '集备主题', width: '', fixed: false, sort: false },
{ prop: 'comment', label: '评论次数', width: '', fixed: false, sort: true },
{ prop: 'join', label: '参与教师数', width: '', fixed: false, sort: true }
],
table_data: [
{ rank: '1', area: '河南区域1', theme: '春', comment: 1, join: 5 },
{ rank: '2', area: '郑州区域2', theme: '春', comment: 8, join: 24 },
{ rank: '3', area: '新疆区域3', theme: '春', comment: 18, join: 52 },
{ rank: '4', area: '江苏区域4', theme: '春', comment: 2, join: 35 },
{ rank: '5', area: '其它区域5', theme: '春', comment: 30, join: 20 }
]
}
实现效果如下:
按照评论次数升序排序如下:
完整代码附上:
<template>
<div class="news-table">
<el-table
:max-height="config.max_height"
:data="config.table_data"
style="width: 100%"
:header-cell-style="{ background: '#212949' }"
>
<el-table-column
align="center"
v-for="(item, index, key) in config.table_cols"
:key="key"
:index="index"
:label="item.label"
:prop="item.prop"
:width="item.width"
:fixed="item.fixed"
:show-overflow-tooltip="true"
:sortable="item.sort"
>
<template slot-scope="scope">
<span>{{ scope.row[item.prop] }}</span>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
export default {
name: 'NewsTable',
props: ["config"],
components: {},
data() {
return {};
},
watch: {},
computed: {},
methods: {},
created() {},
mounted() {}
};
</script>
<style lang="stylus" scoped>
.news-table
/deep/ .el-table {
background-color: rgba(0, 0, 0, 0);
}
/deep/ .el-table::before {
height: 0;
}
/deep/ .el-table th.el-table__cell,
/deep/ .el-table td.el-table__cell {
border-bottom: none;
padding: 0;
color: #FFF;
font-size: 14px;
}
/deep/ .el-table .el-table__header-wrapper {
height: 40px;
line-height: 40px;
}
/deep/ .el-table .el-table__header-wrapper .cell {
white-space: nowrap;
text-overflow: ellipsis;
}
/deep/ .el-table .el-table__row {
height: 40px;
background: #182041;
img {
height: 20px;
vertical-align: middle;
}
&:nth-child(2),
&:nth-child(4) {
background: #212949;
}
}
/deep/ .el-table tbody tr:hover > td {
background: rgba(0, 0, 0, 0);
}
/deep/ .el-table__empty-block {
background: #182041;
}
</style>
后续有新的内容继续更新~