组件化的可编辑数据表格

文章介绍了如何在组件化的环境中动态创建、编辑和管理表格,包括通过JavaScript动态生成表格,实现单元格的点击编辑,以及数据验证和提交的处理。用户可以编辑单元格内容,完成后进行数据验证,验证通过则保存并提交到后台。
摘要由CSDN通过智能技术生成

一、设计思路:

在组件化的可编辑表格中,我们需要考虑以下几点:

  1. 如何动态地创建、删除和修改表格;
  2. 如何实现单元格编辑和保存;
  3. 如何处理表格数据的验证和提交。

根据以上需求,我们可以采用如下的设计思路:

  1. 首先使用JS动态地创建表格,可以通过HTML结构或者JS DOM操作来实现;
  2. 然后为表格的单元格添加点击事件,当单元格被点击时,动态地生成一个可编辑的输入框,并将该输入框显示在单元格内;
  3. 当用户完成单元格内容的编辑后,可以通过确认按钮或者回车键来保存编辑结果;
  4. 我们需要对编辑结果进行验证,例如检查用户输入的数据是否符合规定,如果有错误则需要提示用户并禁止提交;
  5. 如果数据验证通过,可以将表单数据提交到后台服务器进行保存。

二、实现方法:

  1. 动态创建表格

我们可以通过以下JS代码来创建一个简单的表格:

let stutable = document.getElementsByClassName("table")[0];
  1. 单元格编辑

为了实现单元格的编辑功能,我们需要为每个单元格添加一个点击事件,当用户点击单元格时,我们需要动态地创建一个可编辑的输入框,并将其插入到单元格中:

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

// 设置哪些单元格可编辑
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");
    });
  }
  setCellCilck();
}
  1. 数据验证和提交

对于数据验证和提交功能,我们可以在表格外部添加一个按钮或者表单,当用户点击提交按钮时,我们可以遍历所有单元格的值,并将其打包成JSON格式的数据进行提交:

// 更新单元格内容
function updateCell(ele, scorearr) {
  let scoreMax = scorearr[ele.cellIndex - 2];
  scoreMax = scoreMax || 100;
  console.log("当前科目的满分是:" + scoreMax);
  if (document.getElementsByClassName("active-input").length == 0) {
    var oldhtml = ele.innerHTML;
    ele.innerHTML = "";
    var newInput = document.createElement("input");
    newInput.setAttribute("class", "active-input");
    newInput.value = oldhtml;
    newInput.onblur = function () {
      this.value = parseFloat(this.value);
      if (this.value < 0 || this.value > scoreMax) {
        console.log("err");
        addAnimate();
        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) {
              item[i][gradekey[ele.cellIndex]] = parseFloat(this.value);
            }
          }
        }
        console.log("修改后的数据是:", grade_data);
        updateScore();
      }
    };
    newInput.select();
    ele.appendChild(newInput);
    newInput.focus();
  } else {
    return;
  }
}

三、核心代码

html代码:

<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>table</title>
  </head>
  <link rel="stylesheet" href="table.css" />

  <body>
    <div id="tableBox">
      <h2 class="title">可编辑表格</h2>
      <div class="err">成绩输入有误,请重新输入!</div>
      <table class="table">
        <thead>
          <tr></tr>
        </thead>
        <tbody></tbody>
      </table>
    </div>
  </body>
  <script src="table.js"></script>
</html>

js代码:

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

var flag; // 设置是否显示删除栏

// 读取本地json数据
let ajax = new XMLHttpRequest();
ajax.open("get", "data2.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]); // 取出表头数据
      let temp_title = `
                    <th>${titlekey}</th>
                   `;
      stutable_title.insertAdjacentHTML("beforeend", temp_title);
    }
  }
  // 表格内容
  for (item of grade_data) {
    for (let i = 0; i < item.length; i++) {
      gradekey = Object.keys(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>`;
        } else {
          temp_grade += `<td>${item[i][k]}</td>`;
        }
      }
      stutable_grade.insertAdjacentHTML("beforeend", temp_grade);
    }
  }
  totalScoreBar(); // 生成总分栏
  setAllScore([2, 3, 4, 5, 6, 7, 8]); // 设置需要计算总分的学科
  setEditable([2, 3, 4, 5, 6, 7, 8]); // 设置可编辑单元格
  updateScore(); // 更新总分
  flag = true; // 删除栏
  if (flag) actionBar(); // 生成操作栏
}

// 添加总分栏
function totalScoreBar() {
  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");
  }
}

// 添加操作栏
function actionBar() {
  let caozuo = document.createElement("th");
  caozuo.innerText = "操作";
  stutable_title.appendChild(caozuo);
  for (let k = 0; k < stu_trs.length; k++) {
    let caozuo2 = document.createElement("td");
    let btn = document.createElement("button");
    btn.innerText = "删除";
    caozuo2.appendChild(btn);
    stu_trs[k].appendChild(caozuo2);
  }
  delRow(); // 删除操作
}

// 设置哪些单元格可编辑
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");
    });
  }
  setCellCilck();
}

// 设置可计算分数的表格列
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");
    });
  }
}

// 给单元格添加点击事件
function setCellCilck() {
  let scorearr = [150, 150, 150, 100, 100, 100, 100]; // 设计单科成绩的满分
  for (let i = 0; i < editcell.length; i++) {
    editcell[i].onclick = function () {
      updateCell(this, scorearr);
      delRow();
    };
  }
}

// 更新单元格内容
function updateCell(ele, scorearr) {
  let scoreMax = scorearr[ele.cellIndex - 2];
  scoreMax = scoreMax || 100;
  console.log("当前科目的满分是:" + scoreMax);
  if (document.getElementsByClassName("active-input").length == 0) {
    var oldhtml = ele.innerHTML;
    ele.innerHTML = "";
    var newInput = document.createElement("input");
    newInput.setAttribute("class", "active-input");
    newInput.value = oldhtml;
    newInput.onblur = function () {
      this.value = parseFloat(this.value);
      if (this.value < 0 || this.value > scoreMax) {
        console.log("err");
        addAnimate();
        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) {
              item[i][gradekey[ele.cellIndex]] = parseFloat(this.value);
            }
          }
        }
        console.log("修改后的数据是:", grade_data);
        updateScore();
      }
    };
    newInput.select();
    ele.appendChild(newInput);
    newInput.focus();
  } else {
    return;
  }
}

// 添加动画
function addAnimate() {
  thetips.className = "err movedown";
}

// 更新总成绩
function updateScore() {
  // console.log(grades);
  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;
      }
    }
  }
}

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

css代码:

* {
  margin: 0;
  padding: 0;
  --border: 2px solid rgba(121, 121, 121, 1);
}

#tableBox {
  position: relative;
  user-select: none;
}

.table {
  margin: 0 auto;
  border-spacing: 0;
  border-collapse: collapse;
  text-align: center;
  margin-top: 47px;
  z-index: 1;
}

.err {
  display: none;
  top: 95px;
  width: 160px;
  position: absolute;
  margin-left: -100px;
  left: 50%;
  text-align: center;
  padding: 15px 18px;
  background: orange;
  border-radius: 5px;
  font-size: 13px;
  font-weight: 600;
  transition: top 1s;
  z-index: -1;
}
.movedown {
  top: 95px;
  animation: movedown 3s;
}
@keyframes movedown {
  0% {
    top: 95px;
  }
  50% {
    top: 48px;
  }
  100% {
    top: 95px;
  }
}
.title {
  text-align: center;
  padding: 8px 0;
}

tr,
td,
th {
  border: var(--border);
}

th {
  font-weight: 600;
  text-align: center;
  background-color: rgba(204, 204, 204, 1);
}

td > input {
  width: 100px;
  height: 45px;
  border: none;
  font-size: 16px;
}

.table > thead > tr > th,
.table > tbody > tr > td {
  width: 100px;
  height: 45px;
  font-size: 16px;
}

.table > thead > tr {
  font-family: "宋体";
}

button {
  color: #fff;
  background-color: #d9534f;
  border-color: #d43f3a;
  user-select: none;
  border: 1px solid transparent;
  border-radius: 4px;
  cursor: pointer;
  padding: 10px 12px;
  font-size: 14px;
  text-align: center;
}

四、注解

  1. 首先通过JS动态地创建表格,并根据数据创建表头和表体;
  2. 然后遍历表格中的每个单元格,为其添加点击事件;
  3. 当单元格被点击时,动态地生成一个可编辑的输入框,并将输入框显示在单元格内;
  4. 当用户完成单元格内容的编辑后,可以通过回车键来保存编辑结果;
  5. 最后,添加一个提交按钮,当用户点击提交按钮时,遍历表格中的所有单元格的值,并将其打包成JSON格式的数据进行提交。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值