1、前言

在普通的可编辑表格的基础上,改进可编辑表格。数据来自外部的json(模拟服务端),通过json数据生成可编辑表格。根据实际情况,表格没有新增数据功能。表格的可编辑列,计算的列,每列的数据大小,以及是否删除都可进行配置,在修改单元格内容和删除行数据都会映射到相应数据集中。

实现效果:

2、设计思路与方法

  • 现将基本样式写好,将所有的数据写在json文件里。定义两个空数组,通过Ajax将表格的标题和内容成绩读取并分别保存在数组title_data和grade_data里。
  • 定义getHTML方法,先取出每一行的数据,对于表格的表头,通过Object.values()直接取出数据,并通过模板字符串直接渲染到页面中。对于表格内容,通过Object.keys()获取每行数据的键名数组,先定义一个temp_grade并赋值<tr>,通过for in 获取下标并取出每一个键名,判断当前索引值是否等于键名数组的长度减一,若满足条件,则temp_grade加等于td并拼接上</tr>,反之,直接等于td。然后把temp_grade插入到HTML中。在最下方调用totalScoreBar(),actionBar(),setAllScore([2, 3, 4]),setEditable([2, 3, 4]),updateScore()方法,初始化整个表格。
  • 定义totalScoreBar方法用于在thead里添加总分这一列,并通过setAttribute给它设置rname属性值为allgrade。
  • 定义actionBar方法用于在thead里添加操作栏这一列。并在每个tr里添加button标签。
  • 定义flag开关,设置是否调用actionBar方法
  • 定义setEditable方法,用于设置哪些可编辑。传入一个数组arr表示可编辑的单元格列。通过for循环先获取表格行和列,再通过arr.forEach()和setAttribute方法给arr元素表示的那一列单元格设置name为editable。
  • 定义setAllScore方法,用于设置哪些可以计算分数。传入一个数组arr表示可计算的单元格列。通过for循环先获取表格行和列,再通过arr.forEach()和setAttribute方法给arr元素表示的那一列单元格设置class为grade。
  • 定义一个updateScore方法,用来计算分数。通过class取出每行的分数的值,再取出总成绩的值。每个人总成绩等于每行分数相加。
  • 定义一个addAnimate方法,表示单元格输入错误时的动画提示。
  • 定义一个delRow方法,用于表示删除单元格行操作。通过rowindex获取当前行,再定义一个delindex变量,把rowindex-1的值赋给它。然后通过deleteRow(rowindex)删除行。然后取出当前单元格所在行的id为ediId,遍历原始数据。然后取出的当前单元格对应的数据的下标,然后判断ediId是否等于原数组的id,若等于,则删除当前行的数据。
  • 定义setCellCilck方法,用于给class为grade的单元格添加点击事件。在里面定义一个scorearr数组,用于存放各科目的满分成绩。并将该数组传入到updateCell里面。
  • 定义updateCell方法,用于更新单元格的内容。传入ele和定义好的scorearr,表示当前点击的单元格和各个科目满分的数组。先取出当前ele的cellIndex,获取对应的满分数据。然后获取旧的单元格数据并保存为oldhtml。然后创建一个input标签,并传入oldhtml。在input标签的聚焦事件中判断输入的input值是否合法,若不合法,则调用addAnimate方法,弹出error标签的错误提示信息,若合法,则保存当前的值。然后取出当前单元格所在行的id为ediId,遍历原始数据并通过Object.keys()取出键数组。然后取出的当前单元格所在行的列数,然后判断ediId是否等于原数组的id,若等于,则将新的值赋给它,从而实现原数组的修改。

3、源码展示

table.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;

}

table.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>

table.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 = &lt;th&gt;${titlekey}&lt;/th&gt;

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 = &lt;tr&gt;

// 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 += `&lt;td&gt;${item[i][k]}&lt;/td&gt;&lt;/tr&gt;`
} else {
temp_grade += `&lt;td&gt;${item[i][k]}&lt;/td&gt;`
}
}
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 = false; // 删除栏
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 &lt; 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(&quot;修改后的数据是:&quot;, 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);

}

}

}

}

}

}

data2.json

{
"t_title": [
{
"title_name": "学号"
},
{
"title_name": "姓名"
},
{
"title_name": "语文"
},
{
"title_name": "数学"
},
{
"title_name": "英语"
},
{
"title_name": "政治"
},
{
"title_name": "历史"
},
{
"title_name": "地理"
},
{
"title_name": "生物"
}
],
"t_grades": [
{
"id": 1101,
"Student_name": "小王",
"Chinese_score": 98,
"Math_score": 80,
"English_score": 91,
"Political_score":92,
"History_score":86,
"Geographic_score":88,
"Biological_score":96
},
{
"id": 1102,
"Student_name": "小曾",
"Chinese_score": 80,
"Math_score": 80,
"English_score": 80,
"Political_score":93,
"History_score":95,
"Geographic_score":86,
"Biological_score":89
},
{
"id": 1103,
"Student_name": "小赵",
"Chinese_score": 90,
"Math_score": 80,
"English_score": 90,
"Political_score":99,
"History_score":91,
"Geographic_score":98,
"Biological_score":95
},
{
"id": 1104,
"Student_name": "小丽",
"Chinese_score": 90,
"Math_score": 90,
"English_score": 90,
"Political_score":88,
"History_score":78,
"Geographic_score":89,
"Biological_score":100
},
{
"id": 1105,
"Student_name": "小明",
"Chinese_score": 90,
"Math_score": 85,
"English_score": 85,
"Political_score":88,
"History_score":89,
"Geographic_score":100,
"Biological_score":99
},
{
"id": 1106,
"Student_name": "小红",
"Chinese_score": 98,
"Math_score": 82,
"English_score": 96,
"Political_score":92,
"History_score":92,
"Geographic_score":90,
"Biological_score":92
}
]
}

可编辑表格的实现就到这里了,若有问题欢迎留言。

JS 可编辑表格的实现(进阶)的更多相关文章

  1. JS 可编辑表格的实现

    1.实现效果 用户点击语文,数学,英语部分的单元格,可以实现分数的编辑,总分也会随之变化.先看下效果,如图: 2.设计思路 先通过HTML5+CSS3绘制表格,添加input的样式和err提示动画. ...

  2. Vue iview可编辑表格的实现

    创建table实例页 views/table.vue <template> <h1>table page</h1> </template> <sc ...

  3. JS组件系列——表格组件神器:bootstrap table(三:终结篇,最后的干货福利)

    前言:前面介绍了两篇关于bootstrap table的基础用法,这章我们继续来看看它比较常用的一些功能,来个终结篇吧,毛爷爷告诉我们做事要有始有终~~bootstrap table这东西要想所有功能 ...

  4. Jqgrid入门-使用模态对话框编辑表格数据(三)

            Jqgrid是一个强大的表格插件,它提供了多种方式来编辑数据.这三种方式分别是: Cell Editing——只允许修改某一个单元格内容 Inline Editing——允许在jqGr ...

  5. ExtJS4.2学习(七)EditorGrid可编辑表格(转)

    鸣谢地址:http://www.shuyangyang.com.cn/jishuliangongfang/qianduanjishu/2013-11-14/176.html ------------- ...

  6. jQuery实现可编辑表格

    在很多的网页中,这个可编辑表格在许多地方都是非常有用,配合上AJAX技术能够实现很好的用户体验,下面我 们就jQuery来说明一下可编辑表格的实现步骤 首先是HTML代码,非常简单 <!DOCT ...

  7. 实现Easyui 可编辑表格

    一.前端框架使用的easyui框架 二.后端使用的是jfinal 三.效果图 四.html代码 <div id="table_tree" class="easyui ...

  8. 老男孩Day17作业:后台管理平台编辑表格

    一.作业需求: 后台管理平台 ,编辑表格: 1. 非编辑模式: 可对每行进行选择: 反选: 取消选择 2. 编辑模式: 进入编辑模式时如果行被选中,则被选中的行万变为可编辑状态,未选中的不改变 退出编 ...

  9. easyui datagrid可编辑表格使用经验分享

    文章目录 1相关接口方法 2列属性formatter 3编辑器类型 3.1基于my97的编辑器 3.2简单的密码编辑器 3.3动态增加/删除编辑器 4字段的级联操作 4.1combobox的级联操作 ...

随机推荐

  1. linux scsi相关的一些学习笔记

      最近看scsi相关处理的一些备忘,比较零碎,仅作参考. 先从最显而易见的打印入手: [0:0:0:0] disk ATA INTEL SSDSC2BX20 0150 - [0:0:1:0] dis ...

  2. Python 工匠:一个关于模块的小故事

    前言 模块(Module)是我们用来组织 Python 代码的基本单位.很多功能强大的复杂站点,都由成百上千个独立模块共同组成. 虽然模块有着不可替代的用处,但它有时也会给我们带来麻烦.比如,当你接手 ...

  3. Matery主题添加Pjax

    如何给matery主题添加Pjax? Pjax优点 1.减轻服务端压力 2.按需请求,每次只需加载页面的部分内容,而不用重复加载一些公共的资源文件和不变的页面结构,大大减小了数据请求量,以减轻对服务器 ...

  4. C++ 初识函数模板

    1. 前言 什么是函数模板? 理解什么是函数模板,须先搞清楚为什么需要函数模板. 如果现在有一个需求,要求编写一个求 2 个数字中最小数字的函数,这 2 个数字可以是 int类型,可以是 float ...

  5. KingbaseES V8R6集群部署案例之---Windows环境配置主备流复制(异机复制)

    案例说明: 目前KingbaseES V8R6的Windows版本不支持数据库sys_rman的物理备份,可以考虑通过建立主备流复制实现数据库的异机物理备份.本案例详细介绍了,在Windows环境下建 ...

  6. KingbaseES V8R3集群管理和维护案例之---failover切换wal日志变化分析

    ​ 案例说明: 本案例通过对KingbaseES V8R3集群failover切换过程进行观察,分析了主备库切换后wal日志的变化,对应用者了解KingbaseES V8R3(R6) failover ...

  7. python的环境,你再也不用愁-conda

    Conda Guide Conda简介 conda是一个包,依赖和环境管理工具,适用于多种语言,如: Python, R, Scala, Java, Javascript, C/ C++, FORTR ...

  8. 用trie树解决最大异或对问题(On)

    在给定的N个整数A1,A2--ANA1,A2--AN中选出两个进行xor(异或)运算,得到的结果最大是多少? 输入格式 第一行输入一个整数N. 第二行输入N个整数A1A1-ANAN. 输出格式 输出一 ...

  9. 《Java基础——制表符》

    Java基础--制表符       规则: 若前面输出内容不为8的倍数,则通过空格补全. 不足八位,补全八位.   例一:不足八位: System.out.println("123456&q ...

  10. Python实验报告——第3章 流程控制语句

    实验报告 [实验目的] 1.掌握python中流程控制语句的使用,并能够应用到实际开发中. [实验条件] 1.PC机或者远程编程环境 [实验内容] 1.完成第三章流程控制语句实例01-09,实战一到实 ...