uni-app不使用table,手码一个有合并单元格的表格

1,600 阅读3分钟

uni-app不使用table,手码一个有合并单元格的表格

(如果项目急的话直接复制代码,不急的话后面有思路可康康) 效果图 在这里插入图片描述 缺点的话就是高度是固定死的,这个感觉可以实现自适应(现在能用就行),暂时没有自适应就加个点击事件展示内容吧,在H5展示这些表格数据的确不太友好QAQ。

首先先把需要用到的数据挂出来 这个是表格的数据(虽然只是头部的数据,但是头部能合并了,内容自然也比较简单啦),说明下数据的字段分别是什么 树对象结构,然后td代表内容, tdRowspan代表行占多少个单元格(行合并), tdColspan代表列占多少个单元格(列合并)

 packHeader: [
  {
    A: {
      td: "支表支付证书",
      tdRowspan: 1,
      tdColspan: 10,
    },
    B: {
      td: "",
      tdRowspan: 0,
      tdColspan: 0,
    },
    C: {
      td:  "",
      tdRowspan: 0,
      tdColspan: 0,
    },
    D: {
      td: "",
      tdRowspan: 0,
      tdColspan: 0,
    },
    E: {
      td: "",
      tdRowspan: 0,
      tdColspan: 0,
    },
    F: {
      td:  "",
      tdRowspan: 0,
      tdColspan: 0,
    },
    G: {
      td: "",
      tdRowspan: 0,
      tdColspan: 0,
    },
    H: {
      td:  "",
      tdRowspan: 0,
      tdColspan: 0,
    },
    I: {
      td:  "",
      tdRowspan: 0,
      tdColspan: 0,
    },
    J: {
      td: "",
      tdRowspan: 0,
      tdColspan: 0,
    }
  },
  {
    A: {
      td:  "清单号",
      tdRowspan: 2,
      tdColspan: 1,
    },
    B: {
      td:  "清单项目内容",
      tdRowspan: 2,
      tdColspan: 1,
    },
    C: {
      td:  "清单金额",
      tdRowspan: 2,
      tdColspan: 1,
    },
    D: {
      td:  "变更金额",
      tdRowspan: 1,
      tdColspan: 2,
    },
    E: {
      td:  "",
      tdRowspan: 0,
      tdColspan: 0,
    },
    F: {
      td:  "到本期末累计完成",
      tdRowspan: 2,
      tdColspan: 1,
    },
    G: {
      td:  "到上期末累计完成",
      tdRowspan: 2,
      tdColspan: 1,
    },
    H: {
      td:  "本期完成",
      tdRowspan: 2,
      tdColspan: 1,
    },
    I: {
      td: "监理审核本期完成",
      tdRowspan: 2,
      tdColspan: 1,
    },
    J: {
      td: "备注",
      tdRowspan: 2,
      tdColspan: 1,
    }
  },
  {
    A: {
      td:  "",
      tdRowspan: 0,
      tdColspan: 0,
    },
    B: {
      td:  "",
      tdRowspan: 0,
      tdColspan: 0,
    },
    C: {
      td:  "",
      tdRowspan: 0,
      tdColspan: 0,
    },
    D: {
      td:  "本期变更",
      tdRowspan: 1,
      tdColspan: 1,
    },
    E: {
      td:  "监理审核本期变更",
      tdRowspan: 1,
      tdColspan: 1,
    },
    F: {
      td:  "",
      tdRowspan: 0,
      tdColspan: 0,
    },
    G: {
      td:  "",
      tdRowspan: 0,
      tdColspan: 0,
    },
    H: {
      td: "",
      tdRowspan: 0,
      tdColspan: 0,
    },
    I: {
      td:  "",
      tdRowspan: 0,
      tdColspan: 0,
    },
    J: {
      td:  "",
      tdRowspan: 0,
      tdColspan: 0,
    }
  },
  {
    A: {
      td: "",
      tdRowspan: 1,
      tdColspan: 1,
    },
    B: {
      td:  "",
      tdRowspan: 1,
      tdColspan: 1,
    },
    C: {
      td:  "",
      tdRowspan: 1,
      tdColspan: 1,
    },
    D: {
      td: "",
      tdRowspan: 1,
      tdColspan: 1,
    },
    E: {
      td: "",
      tdRowspan: 1,
      tdColspan: 1,
    },
    F: {
      td: "",
      tdRowspan: 1,
      tdColspan: 1,
    },
    G: {
      td: "",
      tdRowspan: 1,
      tdColspan: 1,
    },
    H: {
      td: "",
      tdRowspan: 1,
      tdColspan: 1,
    },
    I: {
      td: "",
      tdRowspan: 1,
      tdColspan: 1,
    },
    J: {
      td: "",
      tdRowspan: 1,
      tdColspan: 1,
    }
  }
],

HTML这块由于app没有dom这一东西所以样式需要一开始定好,判断会有点多 packHeader是上面的数据 letterHeadData是一个["A","B",....."F"] 的数组 等下在js生成

<scroll-view class="scrool-more" scroll-x="true" @scroll="scroll" scroll-left="0">
    <view class="da-table" >
      <view class="da-table-head" >
        <view class="da-table-head-tr"  v-for="(item, index) in packHeader" :key="index" >
            <template v-for="(hitem, hindex) in letterHeadData" >
                <view class="da-table-head-th" :key="hindex"
                :style="(item[hitem].tdColspan && (item[hitem].tdColspan * 1 >= 1) ? 'width:' + item[hitem].tdColspan * 200 + 'px!important;' : 'display:none!important;') + (item[hitem].tdRowspan ? 'height:' + (item[hitem].tdRowspan ) * 40 + 'px!important;' : '') + (item[hitem].tdFloat ? 'position:absolute!important;background:white;z-index:999;' : '')">
                        <text class="da-thead-th-text" > {{ item[hitem].td }} </text>
                </view>
          <!-- 加这个是让哪些格子帮浮动的格子占位置 -->
                <view :key="hindex + 'float'"  v-if="item[hitem].tdFloat "
                :style="(item[hitem].tdColspan ? 'width:' + item[hitem].tdColspan * 200 + 'px!important;display: inline-block!important;visibility: hidden;' : 'display: inline-block!important;') ">
                        <text>看我</text>
                </view>
            </template>
        </view>
      </view>
    </view>
</scroll-view>

接下来是生成letterHeadData 的 JS

// 获取头部字母表头
getlitterTableHead() {
        let azData = this.AZsort()
        let tableLength = Object.keys(this.packHeader[0]).length
        this.letterHeadData = azData.splice(0, tableLength) // 这个记得声明哦
        console.log(this.letterHeadData, tableLength, 'dadada', this.packHeader[0])
},

// 生成数组的
AZsort() {
        let arr = [];
        for (let i = 0; i < 26; i++) {
                arr.push(String.fromCharCode((65 + i)))
                // console.log(String.fromCharCode((65 + i)))  
                // console.log(i)   
        }

        for (let j = 0; j < 26; j++) {
                for (let c = 0; c < 26; c++) {
                        arr.push(arr[j] + arr[c])
                        // console.log(arr[j]+String.fromCharCode((65 + c)))
                }
        }
        return arr;
},

下面展示一些 内联代码片

generateMergeTable() {
        let tableLength = this.packHeader.length // 表格有多少行
        for (let i = 0; i < tableLength; i++) {
                let keyData = this.packHeader[i] // 获取这一行的数据
                // 遍历判断出占两行的单元格让其脱离文档流
                Object.keys(keyData).forEach(key =>{ 
                        console.log(keyData[key].tdRowspan)
                        if (keyData[key].tdRowspan * 1 >= 2) {
                                keyData[key].tdFloat = true 
                                if (i + 1 < tableLength) {
                                        // 第几行
                                        let firstTemp = this.packHeader[i + 1]
                                        // 第几列
                                        firstTemp[key].tdColspan = keyData[key].tdColspan * 1
                                }
                        }
                })
        }

然后就是样式方面的处理了 这个真的比较麻烦点 css

.da-table{
        display: inline-table;
        padding:10px;
        transform: scale(0.7);
        transform-origin: 0 0;
        margin-bottom: 20px;
}

.da-table-head{
        position: relative;
        border-left: 1px solid #5d5d5d;
        border-bottom: 1px solid #5d5d5d;
}

.da-table-head-tr{
        position: relative;
        min-height: 40px;
        display: block;
}

.da-table-head-th{
        border-right:1px solid #5d5d5d;
        border-top: 1px solid #5d5d5d;
        position: relative;
        display: inline-block;
        word-break: normal!important;
        text-align: center;
        padding-left: 10upx;
        vertical-align: top;
        line-height: 40px;
        height: 40px;
        overflow: hidden;
}

.da-table-body {
        border: 1px solid #5d5d5d;
        border-top: 0px;
        border-right: 0px;
}
.da-thead-th-text{
        white-space: normal;
        word-break: break-all;
        font-size:16px;
        overflow: hidden;
        position: absolute;
        top: 48%; /*偏移,居中*/ 
        left: 0;
        right: 0;
        transform: translateY(-50%)!important;
        line-height: 17px;
}
.scrool-more{
        white-space: nowrap; 
        width: 100%;  
        display: inline-block; 
}

思路

最简单的表格肯定没有合并一行一个一个排过去啦 v-for="(item, index) in packHeader" v-for="(hitem, hindex) in letterHeadData" 所以通过循环各自获取键值,遍历出来, 然后就是合并列的,我就想合并列就是把右边的位置占了,宽度变成原来的几倍几倍就行了,刚好我们的数据中没有占位置的tdColspan为0,有位置的就大于0,那有位置的宽度就是,tdColspan * (你想要点宽度)。0 * tdColspan虽然是0,但是又边框在,所以就设置 display:none; 不让其显示就可以啦,(●ˇ∀ˇ●)

合并列的话,有好多要考虑,一个就是你高度改变,旁边单元格没有改变,会造成高度不一致,像这样子 在这里插入图片描述

这时候我就用position:absolute; 高度不会受影响了,但是因为脱离了文档流,使得后面的单元格往左边顶了 在这里插入图片描述 然后就很难受,- -,想了想,要不在浮动元素的底下在加一个假块 占占位置,结果还真可以,绝了。 下面展示一些 内联代码片。 这也就是写这段代码的原因

<view :key="hindex + 'float'"  v-if="item[hitem].tdFloat "
						:style="(item[hitem].tdColspan ? 'width:' + item[hitem].tdColspan * 200 + 'px!important;display: inline-block!important;visibility: hidden;' : 'display: inline-block!important;') ">
							<text>看我</text>
</view>
在 generateMergeTable() 进行数据处理		
这里
// 遍历判断出占两行的单元格让其脱离文档流
			Object.keys(keyData).forEach(key =>{ 
				console.log(keyData[key].tdRowspan)
				if (keyData[key].tdRowspan * 1 >= 2) {
					keyData[key].tdFloat = true 				

在这里插入图片描述 之后又发现下一行的也往左边移动了 原因是因为上面合并,下面这一个的行列占位就变成0了,这时候还是用占位的方法, 下面展示一些 内联代码片。 这个也是generateMergeTable()里面的数据处理,将下一行同个键里面的tdColspan进行处理就可以啦

if (i + 1 < tableLength) {
	// 第几行
	let firstTemp = this.packHeader[i + 1]
	// 第几列
	firstTemp[key].tdColspan = keyData[key].tdColspan * 1
}

在这里插入图片描述 在这里插入图片描述

原创内容,转载需标明来源。