提取组件前


	<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>