html表格table动态合并

效果图如下:

后端给的数据结构如下:

child: [
          {
            type: "沟通领域",
            narrateOne: null,
            completeType: null, //完成情况
          },
          {
            type: "沟通领域",
            narrateOne: null,
            completeType: null, //完成情况
          },
          {
            type: "语言理解领域",
            narrateOne: null,
            completeType: null, //完成情况
          },
          {
            type: "语言理解领域",
            narrateOne: null,
            completeType: null, //完成情况
          },
          {
            type: "语言表达领域",
            narrateOne: null,
            completeType: null, //完成情况
          },
          {
            type: "语言表达领域",
            narrateOne: null,
            completeType: null, //完成情况
          },
        ],

 处理函数如下:

//util.js中
//渲染表格传list,新增行传list和row
export function projectTargetList(list, row) {
    let newList = []
    if (row) {
        list.push(row)
    }
    // 按照 type 属性分类
    let classifiedObject = list.reduce(function (acc, obj) {
        let key = obj.type;
        if (!acc[key]) {
            acc[key] = { type: key, child: [] };
        }
        acc[key].child.push(obj);
        return acc;
    }, {});
    let tempList = Object.values(classifiedObject);
    // console.log(tempList);
    //计算startRow和endRow值
    let tempList2 = tempList.reduce(function (acc, obj, index) {
        let startRow = (index == 0) ? 0 : acc[index - 1].endRow; // 计算 startRow
        let endRow = startRow + obj.child.length; // 计算 endRow
        let rows = obj.child.length
        obj.startRow = startRow;
        obj.endRow = endRow;
        obj.rows = rows
        acc.push(obj);
        return acc;
    }, []);
    // console.log(tempList2);
    tempList2.forEach((item, index) => {
        item.child.forEach((citem, cindex) => {
            citem.startRow = item.startRow
            citem.endRow = item.endRow
            citem.rows = item.rows
            newList.push(citem)
        })
    })
    // console.log(newList);
    return newList
}

 使用:

//目标vue页面中
<template>
<table border="0" cellspacing="0" cellpadding="0">
        <tr>
          <td>训练项目</td>
          <td>训练内容</td>
          <td>完成情况</td>
        </tr>
        <tr v-for="(item, index) in targetList" :key="index">
          <td v-if="item.startRow == index" :rowspan="item.rows">
            <el-input type="textarea" v-model="item.type" autosize></el-input>
          </td>
          <td>
            <el-input
              type="textarea"
              v-model="item.narrateOne"
              autosize
            ></el-input>
          </td>
          <td>
            <el-input
              type="textarea"
              v-model="item.completeType"
              autosize
            ></el-input>
          </td>
          <div v-if="item.endRow - 1 == index" @click="addrow(item, index)">
            <img
              src="../../../../assets/images/addrows.svg"
              alt=""
              style="width: 25px"
            />
          </div>
        </tr>
      </table>
</template>
import { projectTargetList } from "@utils/func";
data() {
    return {
     targetList:[],
    };
},
created() {
//child为请求获取的数据
const child=[
          {
            type: "沟通领域",
            narrateOne: null,
            completeType: null, //完成情况
          },
          {
            type: "沟通领域",
            narrateOne: null,
            completeType: null, //完成情况
          },
          {
            type: "语言理解领域",
            narrateOne: null,
            completeType: null, //完成情况
          },
          {
            type: "语言理解领域",
            narrateOne: null,
            completeType: null, //完成情况
          },
          {
            type: "语言表达领域",
            narrateOne: null,
            completeType: null, //完成情况
          },
          {
            type: "语言表达领域",
            narrateOne: null,
            completeType: null, //完成情况
          },
        ]
   this.targetList=projectTargetList(child,null)
  },
methods: {
//新增行
addrow(item, index) {
      let crow = {
        type: item.type,
        narrateOne: null,
        completeType: null,
      };
      this.targetList= projectTargetList(this.targetList, crow);
    },
}

学习笔记:

根据type合并表格,核心思想是计算出该类type的开始合并行(startRow)、结尾合并行(endRow)、该type的数据条数(rows),再结合v-if,rowspan进行渲染。欢迎交流指教~

### HTML Table动态合并单元格 在HTML `table`中,通过JavaScript可以实现动态合并单元格的功能。这主要涉及到修改`<td>`元素的`colspan`和`rowspan`属性。 对于静态表格结构而言,可以直接在HTML代码里定义这些属性来控制单元格跨越多或多行[^1]。然而,在实际应用中,往往需要基于某些条件逻辑或数据变化而灵活调整哪些单元格应该被合并。此时便需要用到JavaScript编程技术来进行操作。 #### 使用 JavaScript 动态设置 Rowspan 和 Colspan 属性 下面是一个简单的例子展示如何利用JavaScript根据特定规则动态地改变`<td>`标签内的`rowspan`与`colspan`值: ```javascript function adjustTableCells(data) { const table = document.getElementById('myTable'); data.forEach((item, index) => { let row; if (index === 0 || item.group !== data[index - 1].group) { // 创建新行并添加到表体 row = table.insertRow(); // 插入第一个单元格,并设定其跨行数目 const cell1 = row.insertCell(0); cell1.rowSpan = item.rowspan; // 设置跨行数 cell1.innerHTML = item.content; // 如果有其他的数据,则继续插入更多单元格... if ('otherContent' in item){ const cell2 = row.insertCell(cell1.colSpan); cell2.innerHTML = item.otherContent; } } else { // 对于不需要新增行的情况,仅更新现有行中的单元格内容 row.cells[row.cells.length - 1].innerHTML += `<br>${item.content}`; } }); } ``` 此函数接收一个对象数组作为参数,其中每个对象代表一行记录的信息,包括但不限于要显示的内容(`content`)、所属分组(`group`)以及该条目应占用多少行(`rowspan`)。当遇到新的分组时会创建一个新的表格行;如果当前项属于前一项相同的分组,则不会增加额外的行而是将内容追加至最后一内。 为了使上述功能生效,还需要准备相应的HTML部分: ```html <table id="myTable" border="1"> </table> <button onclick="adjustTableCells(sampleData)">Adjust Cells</button> <script type="text/javascript"> const sampleData = [ {"group": "A", "content": "Item A1", "rowspan": 2}, {"group": "A", "content": "Item A2"}, {"group": "B", "content": "Item B1", "rowspan": 1, "otherContent":"Extra Info"} ]; </script> ``` 这段脚本提供了一个按钮点击事件处理器,它调用了之前定义好的`adjustTableCells()`方法并将预设的数据集传递给它。这样就可以看到页面上的表格随着每次点击自动调整其内部单元格布局的效果了。 值得注意的是,这里给出的例子相对简单,适用于基本场景下的动态合并需求。而在更复杂的应用环境中(比如集成Bootstrap框架或是Vue/React组件库),可能还会涉及更多的细节处理和技术选型考量[^2][^4]。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值