纯原生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> 

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

(0)

相关推荐

  • JS对HTML表格进行增删改操作

    要求如下: 写一个html页面,里面有一个表格,储存用户信息,包括:用户名,密码,姓名,邮箱,电话,qq,身份证号.  现在要通过js对表格进行动态的增删改查(只是内存操作即可): 首先,加载页面时用js加载3条初始化记录:  有一个增加记录的按钮,点击后弹出一个div层提供输入,要求各字段必须符合输入格式且不能为空:  用户名:英文+数字+下划线:  密码:英文+数字+下划线+6位以上:  姓名:中文:  邮箱,电话,qq,身份证号符合格式:  每条记录有修改.删除:  修改类似增加,要把原来

  • JS动态增删表格行的方法

    本文实例讲述了JS动态增删表格行的方法.分享给大家供大家参考,具体如下: function insertRow(tableName,className,bgcolor, cellContentArray){ var t = document.getElementByIdx(tableName); //取得table表 var tr = t.insertRow(); //插入一行 tr.className=className; //设置行的css tr.bgcolor=bgcolor; //设置行

  • javascript实现表格增删改操作实例详解

    本文实例讲述了javascript实现表格增删改操作的方法.分享给大家供大家参考.具体实现方法如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"&

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

    公司实习生问我table的增删操作,用jQuery很简单的实现了.又问我不使用jQuery,只使用js如何实现. 面对这种情况,我的一贯做法是'不理解,但是支持'. jQuery用的多了,人也懒了,但还是用js实现了这一操作,觉得难点在于IE兼容... 只是想找代码看看的可以跳过分析过程,文章底部附有完整代码. 以下是coding过程: HTML结构代码 一个基本的table结构,增加了一些简单的样式,三个按钮分别对应创建.清空,和一个预留. <!DOCTYPE HTML> <html&

  • 纯JS将table表格导出到excel的方法

    html <div > <button type="button" onclick="getXlsFromTbl('tableExcel','myDiv')">IE导出Excel方法</button> <button type="button" onclick="method5('tableExcel')">Chrome导出Excel</button> </di

  • JS实现table表格内针对某列内容进行即时搜索筛选功能

    本文实例讲述了JS实现table表格内针对某列内容进行即时搜索筛选功能.分享给大家供大家参考,具体如下: 往往有些时候,我们把数据从数据库读取出来,显示到table里面,而此时来了个新需求,要在一个搜索框内输入关键字,表格的内容进行即时的筛选. 而即时触发进行数据库的查询,再回调显示,就显得慢,拖累服务器,降低用户体验度,这时,要是有个纯js操作,进行表格某列的即时筛选,这样既能提高搜索速度,也不用占用服务器资源,用户自然也满意. 实现如下,先看效果图, 开始状态: 在输入框内输入'e',表格即

  • JS实现table表格固定表头且表头随横向滚动而滚动

    先看一张效果图 思路: 1.头部用一个table并用一个div包裹着, 表格的具体内容用一个table 2.头部外面的div用positon: relative相对定位 3.获取整个表格的高度 4.获取表格的dom(或者包裹着表格的dom)距离页面顶部的距离 offsetTop 5.滚动的零界点的距离 表格的高度+表格距离页面顶部的距离 如果滚动超过这个 就让头部的top值归0或原封不动 当然还有很多可以优化的地方 我只是展示一个小思路 嘿嘿嘿 题外话 为啥用红色表头 因为显眼哇 哈哈 JS代码

  • JS实现table表格数据排序功能(可支持动态数据+分页效果)

    asp.net会经常遇到分页的效果,尤其是希望实现静态的html分页排序(html分页相信大家都已经有自己的解决方案.在这里就不多说).我写了一个简单的Demo排序. 数据就是字母和数字两组.(汉字需要找到asc码) 原理就是利用数组自带的sort排序,进行表格重组.已在.net mvc 中测试过.支持分页.(申明一点.只对当前页面数据排序 无刷新,对所有页面排序的话,肯定需要刷新.这点我还在解决中.)希望有新想法的高手们,给下指点. 下面把html的代码贴出来: <!DOCTYPE HTML

  • 前端必备插件之纯原生JS的瀑布流插件Macy.js

    这是一款非常轻量级的纯原生JS的瀑布流插件--Macy.js,如今图片和视频网站非常多,非常适应瀑布流这样的布局方式来呈现给用户. 这款流布局JS插件仅有4KB的大小,可以说是非常轻量级的哦.配置也比较方便,用户可以自定义间距.列数,还有个特色就是可以定义不同屏幕分辨率,不同列数,这个应用在响应式网页设计是非常方便的. 所以,选择一款简单易用的瀑布流js插件,可以让前端工程师快速开发出漂亮的瀑布流Pc网站和react 后台项目. 瀑布流布局代表网站就是 花瓣网,设计师一定不会陌生的设计网站. 插

  • 纯原生js实现贪吃蛇游戏

    本文实例为大家分享了js实现贪吃蛇游戏的具体代码,供大家参考,具体内容如下 <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=gbk"> <title>贪吃蛇游戏</title> <style type="text/css"> * { margin: 0; padding: 0;

  • 原生JS实现瀑布流插件

    瀑布流布局中的图片有一个核心特点-等宽不定等高,瀑布流布局在国内网网站都有一定规模的使用,比如pinterest.花瓣网等等.那么接下来就基于这个特点开始瀑布流探索之旅. 基础功能实现 首先我们定义好一个有 20 张图片的容器, <body> <style> #waterfall { position: relative; } .waterfall-box { float: left; width: 200px; } </style> </body> <

  • 分享一个自己写的table表格排序js插件(高效简洁)

    像:jQuery的table排序插件(感觉其使用比较麻烦或不清楚其具体用法,就没有使用).原生态js的table排序插件等,最后比较看了下--采用了一个原生态js的table排序插件,并在其基础上做了些修改,虽有些勉强或有些地方使用不太舒服,但最算是比较好的实现了当时需要的功能.而前两天,对原有表格做了点儿修改--增加隔行换色的功能,问题就出现了,--效果错乱:检查分析了下,问题出在其table排序插件代码上--其原代码写的比较难理解,修改还不如重新自己写一个table排序插件. 说写就写,ta

  • 原生JS和JQuery动态添加、删除表格行的方法

    本文实例讲述了原生JS和JQuery动态添加.删除表格行的方法.分享给大家供大家参考.具体分析如下: 下面HTML代码作用:提交一个表单,将复选框的值提交(复选框的值等于后面的文本框,复选框和文本框处在同一行,可以动态添加和删除). 原生态JS版: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"

随机推荐