全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

纯原生js实现table表格的增删

公司实习生问我table的增删操作,用jQuery很简单的实现了。又问我不使用jQuery,只使用js如何实现。

面对这种情况,我的一贯做法是‘不理解,但是支持'。

jQuery用的多了,人也懒了,但还是用js实现了这一操作,觉得难点在于IE兼容。。。

只是想找代码看看的可以跳过分析过程,文章底部附有完整代码。

以下是coding过程:

HTML结构代码

一个基本的table结构,增加了一些简单的样式,三个按钮分别对应创建、清空,和一个预留。

<!DOCTYPE HTML> 
<html> 
 <head> 
 <title>table</title> 
 <meta charset='utf-8' /> 
 <style type="text/css"> 
 table.base{ 
 border-collapse:collapse; 
 text-align: center; 
 border: 1px solid black; 
 } 
 table, tr, td, th{ 
 border: 1px solid black; 
 } 
 </style> 
 </head> 
 <body> 
 <div id="main-content"> 
 <table id="main-table" class="base"> 
 <thead> 
  <tr> 
  <th colspan="3">This is a table for operations by javascript</th> 
  </tr> 
  <tr> 
  <th> 
  <input type="button" value="CREATE" id="cp_btn" onclick="createTr()" /> 
  </th> 
  <th> 
  <input type="button" value="CLEAR" id="cl_btn" onclick="clearTrs()" /> 
  </th> 
  <th> 
  <input type="button" value="GUESS" id="cl_btn"/> 
  </th> 
  </tr> 
 </thead> 
 <tbody> 
 </tbody> 
 </table> 
 </div> 
 </body> 
</html> 

构造函数(伪构造函数)

考虑过,创建一个隐藏的tr,基于此tr执行创建操作。为了不破坏HTML整体结构,决定通过js生成tr对象并append到页面中。

为了在页面加载完成后,再执行dom操作,所以将<script>放在代码下端</body>之前。

基于table中的tbody进行增删操作,可以先声明此全局变量

var vTbody = document.getElementById('main-table').getElementsByTagName('tbody')[0]; 

创建对象,可以使用document.createElement方法。

以面向对象的方式进行编程,先写构造函数(其实并不是标准的构造函数格式),从最内部的元素开始。

td中可能会有text和button等表单元素,所以先创建一个 input 的构造函数function myInput(vId, vClass, vType, vValue, vParent){}

这里有一个兼容性问题,就是IE内核不支持setAttribute(class, value),需要使用setAttribute(className, value),所以为了解决兼容问题,可以通过

setAttribute(class, value) for FF、Chrome..

setAttribute(className, value) for IE

这里采用的是另一种方式 .className,代码如下:

function myInput(vId, vClass, vType, vValue, vParent) { 
 var vInput = document.createElement('input'); 
 if(vId) { 
 vInput.setAttribute('id', vId); 
 } 
 vInput.setAttribute('type', vType); 
 vInput.setAttribute('value', vValue); 
 vInput.className = vClass; 
 if(vParent) { 
 vParent.appendChild(vInput); 
 } 
} 

然后是td对象和tr对象的构造函数,大同小异,代码如下

function myTd(vId, vClass, vChild, vParent) { 
 var vTd = document.createElement('td'); 
 if(vId){ 
 vTd.setAttribute('id', vId); 
 } 
 vTd.className = vClass; 
 if(vChild) { 
 vTd.appendChild(vChild); 
 } 
 if(vParent) { 
 vParent.appendChild(vTd); 
 } 
 return vTd; 
} 
function myTr(vId, vClass, vChild, vParent) { 
 var vTr = document.createElement('tr'); 
 if(vId){ 
 vTr.setAttribute('id', vId); 
 } 
 vTr.className = vClass; 
 if(vChild) { 
 vTr.appendChild(vChild); 
 } 
 if(vParent) { 
 vParent.appendChild(vTr); 
 } 
 return vTr; 
} 

新建行方法createTr()

构造函数完成之后,完善createTr()方法。

预想的tr结构为 序号,文本框,操作按钮。

依次创建相关对象。序号列需要动态刷新,所以先设定class名称,通过方法执行排序操作。

function createTr() { 
 var vTr = new myTr(null, null, null, vTbody); 
 //序列td 
 var vTdSeq = new myTd(null, 'seq', null, vTr); 
 //文本框td 
 var vTdText = new myTd(null, null, null, vTr); 
 var vInputText = new myInput(null, 'td-inp-txt', 'text', '', vTdText); 
 //操作按钮td 
 var vTdBtn = new myTd(null, null, null, vTr); 
 var vInputBtnCp = new myInput(null, 'td-inp-btn-cp', 'button', 'COPY', vTdBtn); 
 var vInputBtnDel = new myInput(null, 'td-inp-btn-del', 'button', 'DELETE', vTdBtn); 
} 

排序方法reSequence()

创建一个动态排序方法reSequence() ,有一个兼容性问题 innerText在火狐下无效果,所以使用innerHTML。代码如下

function reSequence() { 
 var vObj = vTbody.getElementsByClassName('seq'); 
 for (var i=0, len=vObj.length; i<len; i++) { 
 vObj[i].innerHTML = i+1; 
 } 
} 

有一个兼容性问题,IE8及以下不支持getElementsByClassName()方法,网上找到了解决方案

if(!document.getElementsByClassName){ 
 document.getElementsByClassName = function(className, element){ 
 var children = (element || document).getElementsByTagName('*'); 
 var elements = new Array(); 
 for (var i=0; i<children.length; i++){ 
 var child = children[i]; 
 var classNames = child.className.split(' '); 
 for (var j=0; j<classNames.length; j++){ 
 if (classNames[j] == className){ 
  elements.push(child); 
  break; 
 } 
 } 
 } 
 return elements; 
 }; 
} 

试图在Object或者是HTMLTableSectionElement的原型上增加此方法,如

HTMLTableSectionElement.prototype.getElementsByClassName = function(){} 

可惜没有实现。

修改后的代码为

function reSequence() { 
 var vObj = vTbody.getElementsByClassName == null?document.getElementsByClassName('seq', vTbody):vTbody.getElementsByClassName('seq'); 
 for (var i=0, len=vObj.length; i<len; i++) { 
 vObj[i].innerHTML = i+1; 
 } 
} 

除了排序外,还需其他操作,所以我们创建一个init()方法,集中管理reSequence()这些方法,在createTr()方法的结尾调用init()方法。

清空行方法clearTrs()

移除/销毁某个dom对象,首先想到的是remove()方法,不幸的是,存在IE浏览器兼容问题,因此,采用了一个更简便的方式,对dom对象执行innerHTML="",代码如下

function clearTrs() { 
 vTbody.innerHTML = ''; 
} 

IE8报错,'未知的运行错误'。查了以下,因为ie8的table.innerHTML是只读属性,妹的!再改:

function clearTrs() { 
 while(vTbody.rows.length >0) { 
 vTbody.deleteRow(); 
 } 
} 

删除行方法addBtnDelsListener()

接下来,给DELETE按钮绑定删除当前行的方法。

为了解决兼容性问题,网上给出的方法是针对不同浏览器(IE、非IE)分别使用addEventListener、attachEvent方法,

我采用的是另一种解决方案:

obj.onclick = function(){};

匿名函数的方法体,吸取了上面clearTrs()方法的经验教训,直接采用deleteRow(index)方法。

有一点需要注意thisTr.rowIndex获取的行数,比当前行要大2,因为thead中还有两行。所以当前的索引数=thisTr.rowIndex-vThead.rows.length

代码如下:

function addBtnDelsListener() { 
 var vBtnDels = vTbody.getElementsByClassName == null?document.getElementsByClassName('td-inp-btn-del', vTbody):vTbody.getElementsByClassName('td-inp-btn-del'); 
 for (var i=0, len=vBtnDels.length; i<len; i++) { 
 vBtnDels[i].onclick = function() { 
 var vTr = this.parentElement.parentElement; 
 vTbody.deleteRow(vTr.rowIndex-vTbody.parentNode.getElementsByTagName('thead')[0].rows.length); 
 reSequence(); 
 }; 
 } 
} 

执行完删除操作后,通过reSequence()方法重新排序。

同时将addBtnDelsListener()方法加入到init()方法中。

复制行方法addBtnCpsListener()

再来看一下COPY按钮,添加事件监听的方式同上。

如果innerHTML不是只读的话,可以createElement一个tr元素 然后newTr.innerHTML=thisTr.innerHTML,

为了兼容性,必须做些改变。

其实可以将复制看做是新建,唯一的不同在于新建行的文本输入框的内容要等同于被复制行。

这就简单了。我可以先调用createTr()方法,再将最后一个元素lastChild中的文本框的value等于被复制行。

思路有了,代码如下:

function addBtnCpsListener() { 
 var vBtnCps = vTbody.getElementsByClassName == null?document.getElementsByClassName('td-inp-btn-cp', vTbody):vTbody.getElementsByClassName('td-inp-btn-cp'); 
 for (var i=0, len=vBtnCps.length; i<len; i++) { 
 vBtnCps[i].onclick = function() { 
 createTr(); 
 var vNewTr = vTbody.lastChild; 
 var vTr = this.parentElement.parentElement; 
 vNewTr.getElementsByClassName == null?document.getElementsByClassName('td-inp-txt', vNewTr)[0].value = document.getElementsByClassName('td-inp-txt', vTr)[0].value:vNewTr.getElementsByClassName('td-inp-txt')[0].value = vTr.getElementsByClassName('td-inp-txt')[0].value; 
 } 
 } 
} 

优化修改

进行一些优化修改工作:

var elements = new Array();

修改为:var elements = [];

原因:数组用[]更好

addBtnDelsListener方法中的vBtnDels[i].onclick = function() {

修改为:vBtnDels[i].onclick = delTr;

外部新创建一个函数

function delTr() { 
 var vTr = this.parentElement.parentElement; 
 vTbody.deleteRow(vTr.rowIndex-vTbody.parentNode.getElementsByTagName('thead')[0].rows.length); 
 reSequence(); 
 } 

原因:Don't make functions within a loop.

同理,将addBtnCpsListener中的vBtnCps[i].onclick = function() {

修改为:vBtnCps[i].onclick = copyTr;

外部新创建一个函数

<pre code_snippet_id="139791" snippet_file_name="blog_20140103_15_6784659" name="code" class="javascript"> function copyTr() { 
 createTr(); 
 var vNewTr = vTbody.lastChild; 
 var vTr = this.parentElement.parentElement; 
 vNewTr.getElementsByClassName === null? 
 document.getElementsByClassName('td-inp-txt', vNewTr)[0].value = 
 document.getElementsByClassName('td-inp-txt', vTr)[0].value: 
 vNewTr.getElementsByClassName('td-inp-txt')[0].value = 
 vTr.getElementsByClassName('td-inp-txt')[0].value; 
 }</pre> 
<pre></pre> 
<pre></pre> 

copyTr()方法中的?:格式修改为if else函数

修改为:

function copyTr() { 
 createTr(); 
 var vNewTr = vTbody.lastChild; 
 var vTr = this.parentElement.parentElement; 
 if(vNewTr.getElementsByClassName) { 
 vNewTr.getElementsByClassName('td-inp-txt')[0].value = 
 vTr.getElementsByClassName('td-inp-txt')[0].value; 
 } else { 
 document.getElementsByClassName('td-inp-txt', vNewTr)[0].value = 
 document.getElementsByClassName('td-inp-txt', vTr)[0].value; 
 } 
} 

原因:?:预期返回值应该是一个变量or函数,而不应该是一个表达式操作。

有一点需要注意:js最佳实现经常看到要使用===替换==。但是本示例中的==null,如果替换成===null会在ie8一下版本中出现问题。

完整代码

至此,一个完全基于原生JavaScript,并且兼容至IE6的table增删完成了。

还是想吐槽一下,如果不兼容IE10以下的版本,可以节省50%的代码。如果使用jQuery,又可以节省50%的代码。对于实用主义的我而言,这一过程备受煎熬。不过还是从中有所收益的(违心。。)

以下为完整代码:

<!DOCTYPE HTML> 
<html> 
 <head> 
 <title>table</title> 
 <meta charset='utf-8' /> 
 <style type="text/css"> 
 table.base{ 
 border-collapse:collapse; 
 text-align: center; 
 border: 1px solid black; 
 } 
 table, tr, td, th{ 
 border: 1px solid black; 
 } 
 </style> 
 </head> 
 <body> 
 <div id="main-content"> 
 <table id="main-table" class="base"> 
 <thead> 
  <tr> 
  <th colspan="3">This is a table for operations by javascript</th> 
  </tr> 
  <tr> 
  <th> 
  <input type="button" value="CREATE" id="cp_btn" onclick="createTr()" /> 
  </th> 
  <th> 
  <input type="button" value="CLEAR" id="cl_btn" onclick="clearTrs()" /> 
  </th> 
  <th> 
  <input type="button" value="GUESS" id="cl_btn"/> 
  </th> 
  </tr> 
 </thead> 
 <tbody> 
 </tbody> 
 </table> 
 </div> 
 <script type="text/javascript"> 
 if(!document.getElementsByClassName){ 
 document.getElementsByClassName = function(className, element){ 
  var children = (element || document).getElementsByTagName('*'); 
  var elements = []; 
  for (var i=0; i<children.length; i++){ 
  var child = children[i]; 
  var classNames = child.className.split(' '); 
  for (var j=0; j<classNames.length; j++){ 
  if (classNames[j] == className){ 
  elements.push(child); 
  break; 
  } 
  } 
  } 
  return elements; 
 }; 
 } 
 var vTbody = document.getElementById('main-table').getElementsByTagName('tbody')[0]; 
 function myInput(vId, vClass, vType, vValue, vParent) { 
 var vInput = document.createElement('input'); 
 if(vId) { 
  vInput.setAttribute('id', vId); 
 } 
 vInput.setAttribute('type', vType); 
 vInput.setAttribute('value', vValue); 
 vInput.className = vClass; 
 if(vParent) { 
  vParent.appendChild(vInput); 
 } 
 return vInput; 
 } 
 function myTd(vId, vClass, vChild, vParent) { 
 var vTd = document.createElement('td'); 
 if(vId){ 
  vTd.setAttribute('id', vId); 
 } 
 vTd.className = vClass; 
 if(vChild) { 
  vTd.appendChild(vChild); 
 } 
 if(vParent) { 
  vParent.appendChild(vTd); 
 } 
 return vTd; 
 } 
 function myTr(vId, vClass, vChild, vParent) { 
 var vTr = document.createElement('tr'); 
 if(vId){ 
  vTr.setAttribute('id', vId); 
 } 
 vTr.className = vClass; 
 if(vChild) { 
  vTr.appendChild(vChild); 
 } 
 if(vParent) { 
  vParent.appendChild(vTr); 
 } 
 return vTr; 
 } 
 function createTr() { 
 var vTr = new myTr(null, null, null, vTbody); 
 //序列td 
 var vTdSeq = new myTd(null, 'seq', null, vTr); 
 //文本框td 
 var vTdText = new myTd(null, null, null, vTr); 
 var vInputText = new myInput(null, 'td-inp-txt', 'text', '', vTdText); 
 //操作按钮td 
 var vTdBtn = new myTd(null, null, null, vTr); 
 var vInputBtnCp = new myInput(null, 'td-inp-btn-cp', 'button', 'COPY', vTdBtn); 
 var vInputBtnDel = new myInput(null, 'td-inp-btn-del', 'button', 'DELETE', vTdBtn); 
 init(); 
 } 
 function clearTrs() { 
 while(vTbody.rows.length >0) { 
  vTbody.deleteRow(); 
 } 
 } 
 function init(){ 
 reSequence(); 
 addBtnDelsListener(); 
 addBtnCpsListener(); 
 } 
 function reSequence() { 
 var vObj = vTbody.getElementsByClassName == null? 
document.getElementsByClassName('seq', vTbody): 
vTbody.getElementsByClassName('seq'); 
 for (var i=0, len=vObj.length; i<len; i++) { 
  vObj[i].innerHTML = i+1; 
 } 
 } 
 function addBtnDelsListener() { 
 var vBtnDels = vTbody.getElementsByClassName == null? 
document.getElementsByClassName('td-inp-btn-del', vTbody): 
vTbody.getElementsByClassName('td-inp-btn-del'); 
 for (var i=0, len=vBtnDels.length; i<len; i++) { 
  vBtnDels[i].onclick = delTr; 
 } 
 } 
 function delTr() { 
 var vTr = this.parentElement.parentElement; 
 vTbody.deleteRow(vTr.rowIndex-vTbody.parentNode.getElementsByTagName('thead')[0].rows.length); 
 reSequence(); 
 } 
 function addBtnCpsListener() { 
 var vBtnCps = vTbody.getElementsByClassNamenull == null? 
document.getElementsByClassName('td-inp-btn-cp', vTbody): 
vTbody.getElementsByClassName('td-inp-btn-cp'); 
for (var i=0, len=vBtnCps.length; i<len; i++) { 
  vBtnCps[i].onclick = copyTr; 
 } 
 } 
 function copyTr() { 
 createTr(); 
 var vNewTr = vTbody.lastChild; 
 var vTr = this.parentElement.parentElement; 
 if(vNewTr.getElementsByClassName) { 
  vNewTr.getElementsByClassName('td-inp-txt')[0].value = 
  vTr.getElementsByClassName('td-inp-txt')[0].value; 
 } else { 
  document.getElementsByClassName('td-inp-txt', vNewTr)[0].value = 
  document.getElementsByClassName('td-inp-txt', vTr)[0].value; 
 } 
 } 
 </script> 
 </body> 
</html> 

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持!


# js  # 表格  # 增删  # vue.js+Element实现表格里的增删改查  # JS对HTML表格进行增删改操作  # JavaScript获取表格(table)当前行的值、删除行、增加行  # Vue.js实现表格动态增加删除的方法(附源码下载)  # AngularJS实现表格的增删改查(仅限前端)  # javascript实现动态增加删除表格行(兼容IE/FF)  # js操作table元素实现表格行列新增、删除技巧总结  # 使用Bootstrap + Vue.js实现表格的动态展示、新增和删除功能  # JavaScript实现动态增删表格的方法  # javascript实现表格信息增添与删除  # 的是  # 创建一个  # 文本框  # 这一  # 有一个  # 不支持  # 建行  # 需要注意  # 是一个  # 实现了  # 一个函数  # 会有  # 我不  # 放在  # 网上  # 会在  # 问我  # 这就  # 可以通过  # 采用了 


相关文章: 网站制作与设计教程,如何制作一个企业网站,建设网站的基本步骤有哪些?  如何在阿里云高效完成企业建站全流程?  宝塔新建站点报错如何解决?  如何通过智能用户系统一键生成高效建站方案?  子杰智能建站系统|零代码开发与AI生成SEO优化指南  如何快速搭建个人网站并优化SEO?  如何使用Golang table-driven基准测试_多组数据测量函数效率  制作门户网站的参考文献在哪,小说网站怎么建立?  怎么制作网站设计模板图片,有电商商品详情页面的免费模板素材网站推荐吗?  深圳网站制作平台,深圳市做网站好的公司有哪些?  长沙做网站要多少钱,长沙国安网络怎么样?  兔展官网 在线制作,怎样制作微信请帖?  Python文件管理规范_工程实践说明【指导】  小型网站制作HTML,*游戏网站怎么搭建?  武汉外贸网站制作公司,现在武汉外贸前景怎么样啊?  成都品牌网站制作公司,成都营业执照年报网上怎么办理?  建站之星如何防范黑客攻击与数据泄露?  制作网站的软件下载免费,今日头条开宝箱老是需要下载怎么回事?  网站专业制作公司有哪些,做一个公司网站要多少钱?  如何在宝塔面板中创建新站点?  家庭服务器如何搭建个人网站?  制作网站的过程怎么写,用凡科建站如何制作自己的网站?  独立制作一个网站多少钱,建立网站需要花多少钱?  如何快速搭建高效服务器建站系统?  建站主机CVM配置优化、SEO策略与性能提升指南  建站之星如何配置系统实现高效建站?  建站DNS解析失败?如何正确配置域名服务器?  建站之星安装提示数据库无法连接如何解决?  如何用VPS主机快速搭建个人网站?  建站中国必看指南:CMS建站系统+手机网站搭建核心技巧解析  如何设计高效校园网站?  大连网站设计制作招聘信息,大连投诉网站有哪些?  免费网站制作模板下载,除了易企秀之外还有什么H5平台可以制作H5长页面,最好是免费的?  西安大型网站制作公司,西安招聘网站最好的是哪个?  建站上市公司网站建设方案与SEO优化服务定制指南  如何高效搭建专业期货交易平台网站?  如何高效完成独享虚拟主机建站?  深入理解Android中的xmlns:tools属性  如何在搬瓦工VPS快速搭建网站?  官网自助建站系统:SEO优化+多语言支持,快速搭建专业网站  怎么用手机制作网站链接,dw怎么把手机适应页面变成网页?  百度网页制作网站有哪些,谁能告诉我百度网站是怎么联系?  娃派WAP自助建站:免费模板+移动优化,快速打造专业网站  动图在线制作网站有哪些,滑动动图图集怎么做?  jQuery 常见小例汇总  如何配置支付宝与微信支付功能?  建站主机空间推荐 高性价比配置与快速部署方案解析  ,想在网上投简历,哪几个网站比较好?  已有域名和空间,如何快速搭建网站?  深圳网站制作案例,网页的相关名词有哪些? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。