在小程序中使用view、text模拟tr、td,实现table表的绘制与展示。优点是可扩展性强,缺点是无法像富文本一样还原样式。
效果
思路
- 首先选使用什么标签模拟表格,因为没有涉及复杂显示,这里使用基础的
<view>
。其他如cover-view
,再根据需要自行扩展。 - 标签决定好,css布局样式要使用什么来绘制?考虑过后本示例使用
flex
布局,按照每一行来顺序渲染。 - 标签、布局确定好,思考如果通过for循环绘制标签,这里可以先反推,表格的数据如何构建。
先确定一个大致的绘制思路。如下json(假的)
{ "content1": { "tr": { "td": [ { "type": "content", "content": "123" } ], "td": [ { "type": "content", "content": "312" } ] }, "tr": { "td": [ { "type": "content", "content": "123" } ], "td": [ { "type": "content", "content": "312" } ] } } }
- 按照行来拆分,每一行是tr,tr中每一列是td,td中可以再继续差分为内容数组。
- 有了基础数据,思考合并单元格时如何处理?
- 参照原始html的table合并单元格,同样使用
rowspan
\`colspan实现。使用例如
colspan:3`对数据标识。 现在重新整理一下数据结构,得到如下结果。
{ type: 'table', node: [{ "id": "1322", "type": "tr", "node": [{ "type": "td", "node": [{ "type": "content", "content": "" }] }, { "type": "td", "node": [{ "type": "content", "content": "劳动合同" }] }, { "type": "td", "node": [{ "type": "content", "content": "劳务派遣协议" }] } ] }, { "id": "1323", "type": "tr", "node": [{ "type": "td", "node": [{ "type": "content", "content": "1.签订主体" }] }, { "type": "td", "node": [{ "type": "content", "content": "劳务派遣单位与被派遣劳动者" }] }, { "type": "td", "node": [{ "type": "content", "content": "劳务派遣单位与被派遣劳动者" }] } ] }, { "id": "1324", "type": "tr", "node": [{ "type": "td", "rowspan": 3, "node": [{ "type": "content", "content": "2.其他规定" }] }, { "type": "td", "node": [{ "type": "content", "content": "(1)" }, { "id": "2001", "type": "answer", "content": "______" }, { "type": "content", "content": "的固定期限劳动合同,按月支付劳动报酬" } ] }, { "type": "td", "node": [{ "type": "content", "content": "劳务派遣单位应当将劳务派遣协议的内容告知被派遣劳动者" }] } ] }, { "id": "1325", "type": "tr", "node": [{ "type": "td", "node": [{ "type": "content", "content": "" }] }, { "type": "td", "colspan": 2, "node": [{ "type": "content", "content": "(2)被派遣劳动者在无工作期间,劳务派遣单位应当按照所在地人民政府规定的最低工资标准,向其按月支付报酬" }] }] }, { "id": "1326", "type": "tr", "node": [{ "type": "td", "node": [{ "type": "content", "content": "" }] }, { "type": "td", "colspan": 2, "node": [{ "type": "content", "content": "(3)劳务派遣单位和用工单位不得向被派遣劳动者收取费用" }] }] } ] }
- 到这思路大致梳理清晰,尝试写代码实现一下效果。
实现
- 如下代码是在uniapp中编写,为方便运行到微信小程序、抖音小程序。其他端的代码思路大致相同。
- 代码v-for中key注意更改
源码
<template>
<view class="table-body">
<!-- tr 层 -->
<view class="table-tr" v-for="tr in content.node" :key="tr.id">
<!-- td 层 -->
<view class="table-td" :style="[...tableTdStyle(td)]" v-for="(td, index) in tr.node" :key="index">
<!-- td 内容层 -->
<view :style="[...tableTdContentStyle(td)]">
<text class="table-content-text" v-for="(tdNode, index2) in td.node" :key="index2">
{{ tdNode.content }}
</text>
</view>
</view>
</view>
</view>
</template>
<script>
// table td的最小长度 rpx
const minWidth = 450
// table td的最小高度 rpx
const minHeight = 100
export default {
name: 'ExercisesTable',
data() {
return {
content: {
type: 'table',
node: [{
"id": "1322",
"type": "tr",
"node": [{
"type": "td",
"node": [{
"type": "content",
"content": ""
}]
},
{
"type": "td",
"node": [{
"type": "content",
"content": "劳动合同"
}]
},
{
"type": "td",
"node": [{
"type": "content",
"content": "劳务派遣协议"
}]
}
]
},
{
"id": "1323",
"type": "tr",
"node": [{
"type": "td",
"node": [{
"type": "content",
"content": "1.签订主体"
}]
},
{
"type": "td",
"node": [{
"type": "content",
"content": "劳务派遣单位与被派遣劳动者"
}]
},
{
"type": "td",
"node": [{
"type": "content",
"content": "劳务派遣单位与被派遣劳动者"
}]
}
]
},
{
"id": "1324",
"type": "tr",
"node": [{
"type": "td",
"rowspan": 3,
"node": [{
"type": "content",
"content": "2.其他规定"
}]
},
{
"type": "td",
"node": [{
"type": "content",
"content": "(1)"
},
{
"id": "2001",
"type": "answer",
"content": "______"
},
{
"type": "content",
"content": "的固定期限劳动合同,按月支付劳动报酬"
}
]
},
{
"type": "td",
"node": [{
"type": "content",
"content": "劳务派遣单位应当将劳务派遣协议的内容告知被派遣劳动者"
}]
}
]
},
{
"id": "1325",
"type": "tr",
"node": [{
"type": "td",
"node": [{
"type": "content",
"content": ""
}]
}, {
"type": "td",
"colspan": 2,
"node": [{
"type": "content",
"content": "(2)被派遣劳动者在无工作期间,劳务派遣单位应当按照所在地人民政府规定的最低工资标准,向其按月支付报酬"
}]
}]
},
{
"id": "1326",
"type": "tr",
"node": [{
"type": "td",
"node": [{
"type": "content",
"content": ""
}]
}, {
"type": "td",
"colspan": 2,
"node": [{
"type": "content",
"content": "(3)劳务派遣单位和用工单位不得向被派遣劳动者收取费用"
}]
}]
}
]
}
}
},
computed: {
/*
td 自定义样式
*/
tableTdStyle() {
return (item) => {
const {
rowspan,
colspan,
node
} = item
let w = minWidth
let h = minHeight
let style = []
// 如果有colspan 模拟横向合并单元格
if (colspan) {
w = colspan * minWidth
}
// 默认给所有td限制最小宽和最小高
style = [{
"width": `${w}rpx`,
"height": `${h}rpx`
}]
// 默认给所有td添加左右边框
style.push({
"border-left": "1px solid",
// "border-right": "1px solid"
})
// 如果子级有内容,不是空白占位,
// 且 没有竖向合并单元格
// 添加上下border
if (node[0].content && !rowspan) {
style.push({
"border-top": "1px solid",
"border-bottom": "1px solid"
})
}
return style
}
},
/*
td 内容自定义样式
*/
tableTdContentStyle() {
return (item) => {
const {
rowspan,
node
} = item
let w = minWidth
let h = minHeight
let style = []
if (rowspan) {
h = rowspan * minHeight
style = [{
"height": `${h}rpx`
},
{
"position": "absolute",
// bfc
"overflow": "hidden",
"resize": "both"
},
{
"display": "flex"
},
{
"top": 0
},
{
"justify-content": "center"
},
{
"align-items": "center"
},
]
}
return style
}
}
}
}
</script>
<style lang="scss" scoped>
.table-body {
display: inline-flex;
flex-direction: column;
border: 1px solid;
}
.table-tr {
display: inline-flex;
flex-direction: row;
align-items: center;
}
.table-td {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
position: relative;
// 修复border重叠问题
margin: -1px 0px 0px -1px;
}
.table-content-text {
font-size: 26rpx;
letter-spacing: 2rpx;
}
</style>