合并行、合并列、固定表头、固定前两列、动态渲染右边列、行内编辑
一、案例图片说明
1、技术栈:vue2 + elementUI
2、需求:表头固定、表头嵌套、左侧两列固定、左侧第一列合并单元行、右侧列动态加载、右侧单元格行内编辑
3、数据双向绑定:可以【保存】,此处代码就不演示了,保存右侧31列所有数据
4、优化:动态加载列过多,渲染时间长达1分钟,需优化渲染时间
二、.vue单文件:代码说明
- 代码拆解为
<template>、<script>、<style>
- 每个拆解,除了代码中的注释外,代码下方有对应文字解释
- 建议对着数据data来看html,增加理解
- 建议查看
<el-table>
的文档,配合使用更好
1、<template>
<template>
<!-- height - 作用:固定表头,只有写了height才可以固定表头,本案例前3行都是表头 -->
<el-table
border
style="width: 100%;"
v-loading="loading"
:data="detailData.timetableBookVO"
:span-method="objectSpanMethod"
header-cell-class-name="table-header"
row-class-name="table-row-low"
height="80vh"
>
<!-- 左边两列,这两列固定在左边 -->
<!-- fixed - 写着一个就可以了,书架这一列就已经固定了,不管书架这一列下面还有几列 -->
<el-table-column
label="书架"
width="200"
fixed="left"
>
<el-table-column
label="书架说明"
>
<el-table-column
align="center"
prop="bookshelfName"
label="书架"
width="100"
></el-table-column>
<el-table-column
align="center"
prop="bookName"
label="书名"
width="100"
></el-table-column>
</el-table-column>
</el-table-column>
<!-- 右侧动态加载列 -->
<!-- 月份 -->
<el-table-column
:label="detailData.bookshelfNameTitle"
>
<!-- 清扫说明 -->
<el-table-column
:label="detailData.bookshelfContent"
>
<!-- 右侧动态列,此处列为30天 -->
<el-table-column
v-for="date in detailData.dayOfMonth"
width="100"
align="center"
:key="date"
:label="`${date}`"
>
<!-- 行内编辑 -->
<template slot-scope="scope">
<!-- 使用<select>代替<el-select>能大大加快渲染速度 -->
<!-- 若还想加快渲染速度,可以将v-model改为:value,select再加一个change事件,change的时候再更改detailData里面对应的这条数据 -->
<select
class="el-select el-select--small"
v-model="scope.row.timetableDetailVO[fullDate(date)].isCleanedId"
>
<option value="null">请选择</option>
<option v-for="item in isCleanedList" :key="item.id" :value="item.id">{{ item.name }}</option>
</select>
</template>
</el-table-column>
</el-table-column>
</el-table-column>
</el-table>
</template>
- 使用的是
<el-table>
组件 <el-table height="80vh">
height的作用:固定表头,前三行都是表头- 使用
<select>
代替<el-select>
能大大加快渲染速度 - 本案例使用的是
v-model
来进行行内编辑的数据绑定,若还想提升渲染速度,可以试试:value加change事件
手动进行数据绑定,个人实验速度快不了3秒,可以试试
2、<script>
export default {
data() {
return {
detailData: {
id: '',
bookshelfNameTitle: '',
bookshelfContent: '',
dayOfMonth: '',
timetableDate: '',
timetableBookVO: []
},
isCleanedList: [
{ id: 0, name: '未扫' },
{ id: 1, name: '已扫' }
]
}
},
mounted() {
this.queryDetail()
},
methods: {
/**
* 请求数据
* 此处直接使用假数据,本方法用于向后端请求数据
*/
queryDetail() {
this.detailData = {
id: 3,
bookshelfNameTitle: '2023年12月清扫日记',
bookshelfContent: '当前月每本书清扫应大于等于20天,即为清扫任务达标',
// 该月有多少天,用于渲染多少列 - 2023.12有31天,故右侧动态渲染31列
dayOfMonth: 31,
// 该月,用于匹配每本书对应那天的月份
timetableDate: '2024-01',
// 书 - 多少行,就多少条数据
timetableBookVO: [
{
bookshelfId: 1,
bookshelfName: '书架1',
bookId: 11,
bookName: '书架1书籍1',
timetableDetailVO: {
'2024-01-01': { isCleanedId: 0 },
'2024-01-02': { isCleanedId: 0 },
'2024-01-03': { isCleanedId: 0 },
'2024-01-04': { isCleanedId: 0 },
'2024-01-05': { isCleanedId: 1 },
'2024-01-06': { isCleanedId: 1 },
'2024-01-07': { isCleanedId: null },
'2024-01-08': { isCleanedId: null },
'2024-01-09': { isCleanedId: null },
'2024-01-10': { isCleanedId: null },
'2024-01-11': { isCleanedId: null },
'2024-01-12': { isCleanedId: null },
'2024-01-13': { isCleanedId: null },
'2024-01-14': { isCleanedId: null },
'2024-01-15': { isCleanedId: null },
'2024-01-16': { isCleanedId: null },
'2024-01-17': { isCleanedId: null },
'2024-01-18': { isCleanedId: null },
'2024-01-19': { isCleanedId: null },
'2024-01-20': { isCleanedId: null },
'2024-01-21': { isCleanedId: null },
'2024-01-22': { isCleanedId: null },
'2024-01-23': { isCleanedId: null },
'2024-01-24': { isCleanedId: null },
'2024-01-25': { isCleanedId: null },
'2024-01-26': { isCleanedId: null },
'2024-01-27': { isCleanedId: null },
'2024-01-28': { isCleanedId: null },
'2024-01-29': { isCleanedId: null },
'2024-01-30': { isCleanedId: null },
'2024-01-31': { isCleanedId: null },
}
},
{
bookshelfId: 1,
bookshelfName: '书架1',
bookId: 12,
bookName: '书架1书籍2',
timetableDetailVO: {
'2024-01-01': { isCleanedId: 0 },
'2024-01-02': { isCleanedId: 0 },
'2024-01-03': { isCleanedId: 0 },
'2024-01-04': { isCleanedId: 0 },
'2024-01-05': { isCleanedId: 1 },
'2024-01-06': { isCleanedId: 1 },
'2024-01-07': { isCleanedId: null },
'2024-01-08': { isCleanedId: null },
'2024-01-09': { isCleanedId: null },
'2024-01-10': { isCleanedId: null },
'2024-01-11': { isCleanedId: null },
'2024-01-12': { isCleanedId: null },
'2024-01-13': { isCleanedId: null },
'2024-01-14': { isCleanedId: null },
'2024-01-15': { isCleanedId: null },
'2024-01-16': { isCleanedId: null },
'2024-01-17': { isCleanedId: null },
'2024-01-18': { isCleanedId: null },
'2024-01-19': { isCleanedId: null },
'2024-01-20': { isCleanedId: null },
'2024-01-21': { isCleanedId: null },
'2024-01-22': { isCleanedId: null },
'2024-01-23': { isCleanedId: null },
'2024-01-24': { isCleanedId: null },
'2024-01-25': { isCleanedId: null },
'2024-01-26': { isCleanedId: null },
'2024-01-27': { isCleanedId: null },
'2024-01-28': { isCleanedId: null },
'2024-01-29': { isCleanedId: null },
'2024-01-30': { isCleanedId: null },
'2024-01-31': { isCleanedId: null },
}
},
{
bookshelfId: 1,
bookshelfName: '书架1',
bookId: 13,
bookName: '书架1书籍3',
timetableDetailVO: {
'2024-01-01': { isCleanedId: 0 },
'2024-01-02': { isCleanedId: 0 },
'2024-01-03': { isCleanedId: 0 },
'2024-01-04': { isCleanedId: 0 },
'2024-01-05': { isCleanedId: 1 },
'2024-01-06': { isCleanedId: 1 },
'2024-01-07': { isCleanedId: null },
'2024-01-08': { isCleanedId: null },
'2024-01-09': { isCleanedId: null },
'2024-01-10': { isCleanedId: null },
'2024-01-11': { isCleanedId: null },
'2024-01-12': { isCleanedId: null },
'2024-01-13': { isCleanedId: null },
'2024-01-14': { isCleanedId: null },
'2024-01-15': { isCleanedId: null },
'2024-01-16': { isCleanedId: null },
'2024-01-17': { isCleanedId: null },
'2024-01-18': { isCleanedId: null },
'2024-01-19': { isCleanedId: null },
'2024-01-20': { isCleanedId: null },
'2024-01-21': { isCleanedId: null },
'2024-01-22': { isCleanedId: null },
'2024-01-23': { isCleanedId: null },
'2024-01-24': { isCleanedId: null },
'2024-01-25': { isCleanedId: null },
'2024-01-26': { isCleanedId: null },
'2024-01-27': { isCleanedId: null },
'2024-01-28': { isCleanedId: null },
'2024-01-29': { isCleanedId: null },
'2024-01-30': { isCleanedId: null },
'2024-01-31': { isCleanedId: null },
}
},
{
bookshelfId: 2,
bookshelfName: '书架2',
bookId: 21,
bookName: '书架2书籍1',
timetableDetailVO: {
'2024-01-01': { isCleanedId: 0 },
'2024-01-02': { isCleanedId: 0 },
'2024-01-03': { isCleanedId: 0 },
'2024-01-04': { isCleanedId: 0 },
'2024-01-05': { isCleanedId: 1 },
'2024-01-06': { isCleanedId: 1 },
'2024-01-07': { isCleanedId: null },
'2024-01-08': { isCleanedId: null },
'2024-01-09': { isCleanedId: null },
'2024-01-10': { isCleanedId: null },
'2024-01-11': { isCleanedId: null },
'2024-01-12': { isCleanedId: null },
'2024-01-13': { isCleanedId: null },
'2024-01-14': { isCleanedId: null },
'2024-01-15': { isCleanedId: null },
'2024-01-16': { isCleanedId: null },
'2024-01-17': { isCleanedId: null },
'2024-01-18': { isCleanedId: null },
'2024-01-19': { isCleanedId: null },
'2024-01-20': { isCleanedId: null },
'2024-01-21': { isCleanedId: null },
'2024-01-22': { isCleanedId: null },
'2024-01-23': { isCleanedId: null },
'2024-01-24': { isCleanedId: null },
'2024-01-25': { isCleanedId: null },
'2024-01-26': { isCleanedId: null },
'2024-01-27': { isCleanedId: null },
'2024-01-28': { isCleanedId: null },
'2024-01-29': { isCleanedId: null },
'2024-01-30': { isCleanedId: null },
'2024-01-31': { isCleanedId: null },
}
},
{
bookshelfId: 2,
bookshelfName: '书架2',
bookId: 22,
bookName: '书架2书籍2',
timetableDetailVO: {
'2024-01-01': { isCleanedId: 0 },
'2024-01-02': { isCleanedId: 0 },
'2024-01-03': { isCleanedId: 0 },
'2024-01-04': { isCleanedId: 0 },
'2024-01-05': { isCleanedId: 1 },
'2024-01-06': { isCleanedId: 1 },
'2024-01-07': { isCleanedId: null },
'2024-01-08': { isCleanedId: null },
'2024-01-09': { isCleanedId: null },
'2024-01-10': { isCleanedId: null },
'2024-01-11': { isCleanedId: null },
'2024-01-12': { isCleanedId: null },
'2024-01-13': { isCleanedId: null },
'2024-01-14': { isCleanedId: null },
'2024-01-15': { isCleanedId: null },
'2024-01-16': { isCleanedId: null },
'2024-01-17': { isCleanedId: null },
'2024-01-18': { isCleanedId: null },
'2024-01-19': { isCleanedId: null },
'2024-01-20': { isCleanedId: null },
'2024-01-21': { isCleanedId: null },
'2024-01-22': { isCleanedId: null },
'2024-01-23': { isCleanedId: null },
'2024-01-24': { isCleanedId: null },
'2024-01-25': { isCleanedId: null },
'2024-01-26': { isCleanedId: null },
'2024-01-27': { isCleanedId: null },
'2024-01-28': { isCleanedId: null },
'2024-01-29': { isCleanedId: null },
'2024-01-30': { isCleanedId: null },
'2024-01-31': { isCleanedId: null },
}
},
{
bookshelfId: 3,
bookshelfName: '书架3',
bookId: 31,
bookName: '书架3书籍1',
timetableDetailVO: {
'2024-01-01': { isCleanedId: 0 },
'2024-01-02': { isCleanedId: 0 },
'2024-01-03': { isCleanedId: 0 },
'2024-01-04': { isCleanedId: 0 },
'2024-01-05': { isCleanedId: 1 },
'2024-01-06': { isCleanedId: 1 },
'2024-01-07': { isCleanedId: null },
'2024-01-08': { isCleanedId: null },
'2024-01-09': { isCleanedId: null },
'2024-01-10': { isCleanedId: null },
'2024-01-11': { isCleanedId: null },
'2024-01-12': { isCleanedId: null },
'2024-01-13': { isCleanedId: null },
'2024-01-14': { isCleanedId: null },
'2024-01-15': { isCleanedId: null },
'2024-01-16': { isCleanedId: null },
'2024-01-17': { isCleanedId: null },
'2024-01-18': { isCleanedId: null },
'2024-01-19': { isCleanedId: null },
'2024-01-20': { isCleanedId: null },
'2024-01-21': { isCleanedId: null },
'2024-01-22': { isCleanedId: null },
'2024-01-23': { isCleanedId: null },
'2024-01-24': { isCleanedId: null },
'2024-01-25': { isCleanedId: null },
'2024-01-26': { isCleanedId: null },
'2024-01-27': { isCleanedId: null },
'2024-01-28': { isCleanedId: null },
'2024-01-29': { isCleanedId: null },
'2024-01-30': { isCleanedId: null },
'2024-01-31': { isCleanedId: null },
}
},
]
}
},
/**
* 日期匹配 - 全日期
*/
fullDate(date) {
return `${this.detailData.timetableDate}-${date > 9 ? date : '0' + date}`
},
/**
* 合并行 - 书架
*/
objectSpanMethod({ row, column, rowIndex, columnIndex }) {
const { timetableBookVO } = this.detailData
const listMap = {}
timetableBookVO.length && timetableBookVO.forEach((item, index) => {
if (listMap[item.bookshelfId]) {
// len - 用于书架合并多少行
listMap[item.bookshelfId].len += 1
// firstIndex - 用于同一个书架,最开始的书架进行合并,例如书架1,有3本书,则第一本书的书架1合并3行,后面都为0即可
listMap[item.bookshelfId].firstIndex = listMap[item.bookshelfId].firstIndex < index ? listMap[item.bookshelfId].firstIndex : index
} else {
listMap[item.bookshelfId] = { len: 1, firstIndex: index }
}
})
if (columnIndex == 0) {
if (listMap[row.bookshelfId] && listMap[row.bookshelfId].firstIndex == rowIndex) {
return { rowspan: listMap[row.bookshelfId].len, colspan: 1 }
} else {
return { rowspan: 0, colspan: 0 }
}
}
}
}
}
- 本案例:假数据代替后端请求
- 合并行用于表身的书架列,同一个书架可能拥有多本书,那同一个书架则合并行
3、<style>
.el-select--small {
height: 32px;
line-height: 32px;
font-size: 14px;
color: #606266;
word-break: break-all;
border-radius: 4px;
border: 1px solid #EBEEF5;
background-color: #FFFFFF;
width: 100%;
}
- 此处为.scss代码,作用:对原生select选择框的一个样式优化
- 根据个人需求进行更改