提取组件前#
<template>
<view class="container">
<view class="table-wrap">
<view class="table-content">
<view class="tr header-row">
<view
v-for="(col, index) in columns"
:key="index"
class="th"
:class="{
'fixed-col': col.fixed,
'stretch-col': index === columns.length - 1 && !col.fixed
}"
:style="{ width: col.width, left: col.fixed ? '0' : 'auto' }"
>
{{ col.label }}
</view>
</view>
<view class="tr body-row" v-for="(row, rowIndex) in tableData" :key="rowIndex">
<view
v-for="(col, colIndex) in columns"
:key="colIndex"
class="td"
:class="{
'fixed-col': col.fixed,
'stretch-col': colIndex === columns.length - 1 && !col.fixed
}"
:style="{ width: col.width, left: col.fixed ? '0' : 'auto' }"
>
{{ row[col.prop] }}
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
columns: [
{ label: '编号', prop: 'id', width: '150rpx', fixed: true },
{ label: '姓名', prop: 'name', width: '200rpx' },
{ label: '年龄', prop: 'age', width: '150rpx' },
{ label: '部门', prop: 'dept', width: '200rpx' },
{ label: '职位', prop: 'job', width: '200rpx' },
{ label: '入职时间', prop: 'date', width: '260rpx' },
{ label: '备注信息', prop: 'remark', width: '400rpx' }
],
tableData: []
};
},
mounted() {
this.loadData();
},
methods: {
loadData() {
const list = [];
for (let i = 1; i <= 20; i++) {
list.push({
id: `100${i}`,
name: `测试用户${i}`,
age: 20 + i,
dept: '研发中心',
job: '前端工程师',
date: '2023-11-01',
remark: i % 3 === 0 ? '这是一个非常长非常长非常长非常长非常长非常长非常长的备注文本,用于测试单元格的自动换行功能和固定列的自动撑高对齐效果。' : '测试文本较短。'
});
}
this.tableData = list;
}
}
};
</script>
<style scoped>
.container {
height: 100vh;
background-color: #fff;
display: flex;
flex-direction: column;
}
.table-wrap {
flex: 1;
height: 0;
overflow: auto;
position: relative;
}
.table-content {
display: inline-block;
min-width: 100%;
}
.tr {
display: flex;
width: 100%;
white-space: normal;
align-items: stretch;
}
.th, .td {
display: flex;
align-items: center;
justify-content: flex-start;
text-align: left;
box-sizing: border-box;
padding: 10rpx;
border-right: 1px solid #e8e8e8;
border-bottom: 1px solid #e8e8e8;
flex-shrink: 0;
font-size: 28rpx;
background-color: #fff;
line-height: 1.4;
}
.stretch-col {
flex-grow: 1;
width: 0 !important;
min-width: 150rpx;
}
.header-row {
position: sticky;
top: 0;
z-index: 10;
height: 80rpx;
background-color: #dcdfe6;
}
.th {
background-color: #ebeef5;
font-weight: bold;
color: #606266;
border-bottom: 1px solid #ebeef5;
height: 100%;
}
.fixed-col {
position: sticky;
left: 0;
z-index: 5;
border-right: 1px solid #dcdfe6;
}
.header-row .fixed-col {
z-index: 20;
}
.body-row:hover .td {
background-color: #f5f7fa;
}
</style>
提取组件#
<template>
<view class="container">
<view class="table-wrap">
<view class="table-content">
<view class="tr header-row">
<view
v-for="(col, index) in columns"
:key="index"
class="th"
:class="{
'fixed-col': col.fixed,
'stretch-col': index === columns.length - 1 && !col.fixed
}"
:style="{ width: col.width, left: col.fixed ? '0' : 'auto' }"
>
{{ col.label }}
</view>
</view>
<view class="tr body-row" v-for="(row, rowIndex) in tableData" :key="rowIndex">
<view
v-for="(col, colIndex) in columns"
:key="colIndex"
class="td"
:class="{
'fixed-col': col.fixed,
'stretch-col': colIndex === columns.length - 1 && !col.fixed
}"
:style="{ width: col.width, left: col.fixed ? '0' : 'auto' }"
>
{{ row[col.prop] }}
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
/**
* label:列名称,
* prop: 对应 tableData 中数据的键名 (key),用于内容映射
* width: 宽度
* fixed: 是否将该列固定在左侧。目前组件仅支持固定最左侧的第一列。
*/
columns: {
type: Array,
required: true,
default: () => []
},
tableData: {
type: Array,
required: true,
default: () => []
}
}
};
</script>
<style scoped>
.container {
height: 100%;
background-color: #fff;
display: flex;
flex-direction: column;
}
.table-wrap {
flex: 1;
height: 0;
overflow: auto;
position: relative;
}
.table-content {
display: inline-block;
min-width: 100%;
}
.tr {
display: flex;
width: 100%;
white-space: normal;
align-items: stretch;
}
.th, .td {
display: flex;
align-items: center;
justify-content: center;
text-align: center;
box-sizing: border-box;
padding: 10rpx;
border-right: 1px solid #e8e8e8;
border-bottom: 1px solid #e8e8e8;
flex-shrink: 0;
font-size: 28rpx;
background-color: #fff;
line-height: 1.4;
}
.stretch-col {
flex-grow: 1;
min-width: 150rpx;
}
.header-row {
position: sticky;
top: 0;
z-index: 10;
height: 80rpx;
}
.th {
background-color: #ebeef5;
font-weight: bold;
color: #606266;
border-bottom: 1px solid #ebeef5;
height: 100%;
}
.fixed-col {
position: sticky;
left: 0;
z-index: 5;
border-right: 1px solid #dcdfe6;
}
.header-row .fixed-col {
z-index: 20;
}
.body-row:hover .td {
background-color: #f5f7fa;
}
</style>