公司实习生问我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"color: #000000">除了排序外,还需其他操作,所以我们创建一个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"htmlcode">function addBtnCpsListener() { var vBtnCps = vTbody.getElementsByClassName == null"color: #000000">优化修改进行一些优化修改工作:
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"color: #000000">copyTr()方法中的"color: #000000">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; } }原因:"htmlcode">
<!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>以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持!
DDR爱好者之家 Design By 杰米
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
P70系列延期,华为新旗舰将在下月发布
3月20日消息,近期博主@数码闲聊站 透露,原定三月份发布的华为新旗舰P70系列延期发布,预计4月份上市。
而博主@定焦数码 爆料,华为的P70系列在定位上已经超过了Mate60,成为了重要的旗舰系列之一。它肩负着重返影像领域顶尖的使命。那么这次P70会带来哪些令人惊艳的创新呢?
根据目前爆料的消息来看,华为P70系列将推出三个版本,其中P70和P70 Pro采用了三角形的摄像头模组设计,而P70 Art则采用了与上一代P60 Art相似的不规则形状设计。这样的外观是否好看见仁见智,但辨识度绝对拉满。
更新日志
- 凤飞飞《我们的主题曲》飞跃制作[正版原抓WAV+CUE]
- 刘嘉亮《亮情歌2》[WAV+CUE][1G]
- 红馆40·谭咏麟《歌者恋歌浓情30年演唱会》3CD[低速原抓WAV+CUE][1.8G]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[320K/MP3][193.25MB]
- 【轻音乐】曼托凡尼乐团《精选辑》2CD.1998[FLAC+CUE整轨]
- 邝美云《心中有爱》1989年香港DMIJP版1MTO东芝首版[WAV+CUE]
- 群星《情叹-发烧女声DSD》天籁女声发烧碟[WAV+CUE]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[FLAC/分轨][748.03MB]
- 理想混蛋《Origin Sessions》[320K/MP3][37.47MB]
- 公馆青少年《我其实一点都不酷》[320K/MP3][78.78MB]
- 群星《情叹-发烧男声DSD》最值得珍藏的完美男声[WAV+CUE]
- 群星《国韵飘香·贵妃醉酒HQCD黑胶王》2CD[WAV]
- 卫兰《DAUGHTER》【低速原抓WAV+CUE】
- 公馆青少年《我其实一点都不酷》[FLAC/分轨][398.22MB]
- ZWEI《迟暮的花 (Explicit)》[320K/MP3][57.16MB]