Uniapp Vue Table上下左右滚动
提取组件前 <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>