组件化的可编辑数据表格

目录

要求

设计思路

实现方法及核心代码

html

data.josn

定义变量

添加总分栏

需要计算的列

计算总分

设置单元格可编辑

删除某行数据

添加删除按钮

更新单元格内容

读取本地json数据

渲染Dom内容

总结


要求

  1. 需要通过以上JSON格式的数组(数据自拟,建议数据对象不少于3个属性)生成可编辑表格,并且能灵活配置可编辑的数据列。

  2. 能分别为不同的可编辑列提供验证规则。

  3. 能配置和实现数据行的可删除操作。

  4. 数据修改能直接映射到从JSON生成的数据对象(该对象可作为缓存,以备提交到服务器)中。

设计思路

  1. 设计一个学生成绩表,实现可以修改学生分数,自动计算学生总分,可以删除学生数据等功能。

  2. table标签搭建表格的主体框架。

  3. 在json文件中创建表格数据。

  4. 定义totalScore方法添加总分栏。

  5. 定义setAllScore方法设置需计算的列

  6. 定义updateScore方法计算总分。

  7. 定义setEditable方法设置表格的可编辑列。

  8. 增加删除按钮,并定义delRow方法,用于删除某一行数据。

  9. 定义updateCell方法,用来更新单元格的内容。

  10. 读取json数据。

实现方法及核心代码

html

搭建表格框架

<div id="container">
      <h1>可编辑表格</h1>
      <div class="err">出成绩输入错误,请重新输入</div>
      <table class="table" border="1">
        <thead>
          <!-- 定义表格的标题行 -->
          <tr></tr>
        </thead>
        <!-- 定义表格的主体 -->
        <tbody></tbody>
      </table>
    </div>

data.josn

创建表格数据

{
  "t_title": [
    {
      "title_name": "学号"
    },
    {
      "title_name": "姓名"
    },
    {
      "title_name": "语文"
    },
    {
      "title_name": "数学"
    },
    {
      "title_name": "英语"
    }
  ],
  "t_grades": [
    {
      "id": 1001,
      "Student_name": "小红",
      "Chinese_score": 98,
      "Math_score": 80,
      "English_score": 91
    },
    {
      "id": 1002,
      "Student_name": "小曾",
      "Chinese_score": 80,
      "Math_score": 80,
      "English_score": 80
    },
    {
      "id": 1003,
      "Student_name": "小赵",
      "Chinese_score": 90,
      "Math_score": 80,
      "English_score": 90
    },
    {
      "id": 1004,
      "Student_name": "小丽",
      "Chinese_score": 90,
      "Math_score": 90,
      "English_score": 90
    },
    {
      "id": 1005,
      "Student_name": "小明",
      "Chinese_score": 90,
      "Math_score": 85,
      "English_score": 85
    },
    {
      "id": 1006,
      "Student_name": "小华",
      "Chinese_score": 98,
      "Math_score": 82,
      "English_score": 96
    }
  ]
}

定义变量

let stutable = document.getElementsByClassName("table")[0];
    let stutable_title = stutable
      .getElementsByTagName("thead")[0]
      .getElementsByTagName("tr")[0]; // 获取th标题行
    let stutable_grade = stutable.getElementsByTagName("tbody")[0]; // 获取tbody
    let stu_trs = stutable_grade.getElementsByTagName("tr"); // 获取tbody的tr标签

    var title_data = []; // 存放标题数据
    var grade_data = []; // 存放成绩数据
    let delbtns = document.getElementsByTagName("button");

    var editcell = document.getElementsByName("editable"); // 可编辑的单元格
    var grades = document.getElementsByClassName("grade"); // 需要计算的单元格
    var thetips = document.getElementsByClassName("err")[0];
    var alltr = document.getElementsByTagName("tr"); // 获取HTML中所有的tr标签

添加总分栏

定义totalScore方法,用于在thead里添加总分这一列,并通过setAttribute给它设置rname属性值为allgrade。

 function totalScore() {
        let allscore = document.createElement("th");
        allscore.innerText = "总分";
        stutable_title.appendChild(allscore);
        for (let j = 0; j < stu_trs.length; j++) {
          let score = document.createElement("td");
          score.innerText = "0";
          stu_trs[j].appendChild(score);
          score.setAttribute("rname", "allgrade");
        }
      }

需要计算的列

定义setAllScore方法,用于设置哪些可以计算分数。传入一个数组arr表示可计算的单元格列。通过for循环先获取表格行和列,再通过arr.forEach()和setAttribute方法给arr元素表示的那一列单元格设置class为grade。

function setAllScore(arr) {
      // arr 表示需要计算总分的单元格
      var strow = stutable.rows.length; // 获取表格行数
      for (let i = 1; i < strow; i++) {
        let stcell = stutable.rows[i].cells; // 获取表格列数
        arr.forEach(function (item) {
          stcell[item].setAttribute("class", "grade");
        });
      }
    }

计算总分

定义updateScore方法,用来计算分数。通过class取出每行的分数的值,再取出总成绩的值。每个人总成绩等于每行分数相加。

function updateScore() {
        for (let n = 1; n < alltr.length; n++) {
          var grade01 =
            grades[n].parentNode.parentNode.children[n - 1].querySelectorAll(
              "td[class]"
            ); //取出每行的分数的值
          var grade02 =
            grades[n].parentNode.parentNode.children[n - 1].querySelectorAll(
              "td[rname]"
            ); //取出总成绩的值
          var sum = 0;
          for (let i = 0; i < grade01.length; i++) {
            sum += parseFloat(grade01[i].innerHTML);
            for (let j = 0; j < grade02.length; j++) {
              grade02[j].innerHTML = sum;
            }
          }
        }
      }

设置单元格可编辑

定义setEditable方法,用于设置哪些可编辑。传入一个数组arr表示可编辑的单元格列。通过for循环先获取表格行和列,再通过arr.forEach()和setAttribute方法给arr元素表示的那一列单元格设置name为editable。

 function setEditable(arr) {
        //arr 表示可编辑的单元格
        // editable 设置单元格可编辑性
        var strow = stutable.rows.length; // 获取表格行数
        for (let i = 1; i < strow; i++) {
          let stcell = stutable.rows[i].cells; // 获取表格列数
          // console.log(stcell);
          arr.forEach(function (item) {
            stcell[item].setAttribute("name", "editable");
          });
        }
      
      }

删除某行数据

定义一个delRow方法,用于删除单元格行。通过rowindex获取当前行,再定义一个delindex变量,把rowindex-1的值赋给它。然后通过deleteRow(rowindex)删除行。然后取出当前单元格所在行的id为ediId,遍历原始数据。然后取出的当前单元格对应的数据的下标,然后判断ediId是否等于原数组的id,若等于,则删除当前行的数据。

 function delRow() {
        for (let i = 0; i < delbtns.length; i++) {
          delbtns[i].onclick = function () {
            let rowindex = this.parentNode.parentNode.rowIndex; // 获取当前行
            stutable.deleteRow(rowindex);
            /*    映射数据表    */
            let ediId = this.parentNode.parentNode.children[0].innerHTML; // 获取当前单元格的id
            console.log(item);
            for (item of grade_data) {
              for (let i = 0; i < item.length; i++) {
                if (item[i].id == ediId) {
                  item.splice(rowindex - 1, 1);
                }
              }
            }
          };
        }
      }

添加删除按钮

function del() {
        let delinput = document.createElement("th");
        delinput.innerText = "操作";
        stutable_title.appendChild(delinput);
        for (let k = 0; k < stu_trs.length; k++) {
          let del = document.createElement("td");
          let btn = document.createElement("button");
          btn.innerText = "删除";
          del.appendChild(btn);
          stu_trs[k].appendChild(del);
        }
      }

更新单元格内容

定义updateCell方法,用来更新单元格的内容。oldhtml和newhtml来分别保存原有的表格内容和修改后的表格内容。通过input标签的聚焦事件中判断输入的input值是否合法,当输入的数据不满足条件时,显示错误提示。

function updateCell(ele, scorearr) {
        let scoreMax = 100; //最大值为100
        if (document.getElementsByClassName("active-input").length == 0) {
          var oldhtml = ele.innerHTML;
          ele.innerHTML = "";
          var newInput = document.createElement("input"); //创建元素节点input,用来接收修改后的数据
          newInput.setAttribute("class", "active-input"); //设置input的class为active-input
          newInput.value = oldhtml;
          newInput.onblur = function () {
            //input标签的聚焦事件中判断输入的input值是否合法
            this.value = parseFloat(this.value);
            if (this.value < 0 || this.value > scoreMax) {
              //输入的数据不满足条件时,显示错误提示
              thetips.style.display = "block";
              return;
            } else {
              thetips.style.display = "none";
              ele.innerHTML = this.value == oldhtml ? oldhtml : this.value;

              /*    映射数据表    */
              // 取出当前单元格数据
              let ediId = ele.parentNode.children[0].innerHTML; // 获取当前修改的单元格的id
              // console.log(ediId);
              for (item of grade_data) {
                for (let i = 0; i < item.length; i++) {
                  // 取出数据集的所有键名
                  let gradekey = Object.keys(item[i]);
                  // console.log(item[i].id); // 取出数据集的id
                  // console.log(ele.cellIndex); // 输出当前单元格所在行的列数
                  if (item[i].id == ediId) {
                    //判断ediId是否等于原数组的id,若相等,则将新的值赋给它,从而实现原数组的修改
                    item[i][gradekey[ele.cellIndex]] = parseFloat(this.value);
                  }
                }
              }
              console.log("修改后的数据是:", grade_data);
              updateScore();
            }
          };
          newInput.select();
          ele.appendChild(newInput);
          newInput.focus();
        } else {
          return;
        }
      }

读取本地json数据

定义两个空数组title_data和grade_data,通过Ajax将表格的标题和内容成绩读取并分别保存在数组title_data和grade_data里。

let ajax = new XMLHttpRequest();
      ajax.open("get", "data.json");
      ajax.send();
      ajax.onreadystatechange = function () {
        if (ajax.readyState == 4 && ajax.status == 200) {
          let alldata = JSON.parse(ajax.responseText);
          title_data.push(alldata.t_title); // 学生信息栏数据
          grade_data.push(alldata.t_grades); // 学生成绩栏数据
          getHtml(); // 生成HTML
        }
      };

渲染Dom内容

function getHtml() {
      let titlekey, gradekey; // 用于存放对象的key
      // 表头
      for (item of title_data) {
        for (let i = 0; i < item.length; i++) {
          titlekey = Object.values(item[i]); // 取出表头数据
          // console.log(titlekey);
          let temp_title = `<th>${titlekey}</th>`;
          //console.log(temp_title);

          stutable_title.insertAdjacentHTML("beforeend", temp_title); //插入元素内部的最后一个子节点之后
          // console.log(stutable_title);
        }
      }
      // 表格内容
      for (item of grade_data) {
        for (let i = 0; i < item.length; i++) {
          gradekey = Object.keys(item[i]);
          // console.log(item[i]);
          let temp_grade = `<tr>`;
          console.log(gradekey); // 获取到的key数组
          for (let j in gradekey) {
            let k = gradekey[j]; // 获取到的key值
            console.log(item[i][k]); // 取出对象中的值

            // 判断是否是最后一个键名
            if (j == gradekey.length - 1) {
              //判断当前索引值是否等于键名数组的长度减一
              temp_grade += `<td>${item[i][k]}</td></tr>`; //满足条件,则temp_grade加等于td并拼接上</tr>
            } else {
              temp_grade += `<td>${item[i][k]}</td>`;
            }
          }
          stutable_grade.insertAdjacentHTML("beforeend", temp_grade);
        }
      }
      totalScore(); // 生成总分栏
      del(); //删除操作栏
      setAllScore([2, 3, 4]); // 设置需要计算总分的学科
      //setEditable([2, 3, 4]); // 设置可编辑单元格
      updateScore(); // 更新总分
    }

总结

  1. 该表格可以实现可编辑、计算总分、删除数据、更改数据等功能。
  2. 因为只能修改该表格的成绩列,只有一种验证规则,所以没能实现分别为不同的可编辑列提供验证规则。
  3. 修改后的数据只能通过在控制台上查看到,并没有真正修改到本地的data.json文件中的数据。
  4. 在修改成绩时,如果输入的数据不是数字不会提示错误,而是显示NaN,总成绩将变成NaN。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值