国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發(fā) > JS > 正文

純原生js實現(xiàn)table表格的增刪

2024-05-06 16:34:23
字體:
供稿:網(wǎng)友

公司實習(xí)生問我table的增刪操作,用jQuery很簡單的實現(xiàn)了。又問我不使用jQuery,只使用js如何實現(xiàn)。

面對這種情況,我的一貫做法是‘不理解,但是支持'。

jQuery用的多了,人也懶了,但還是用js實現(xiàn)了這一操作,覺得難點在于IE兼容。。。

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

以下是coding過程:

HTML結(jié)構(gòu)代碼

一個基本的table結(jié)構(gòu),增加了一些簡單的樣式,三個按鈕分別對應(yīng)創(chuàng)建、清空,和一個預(yù)留。

<!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> 

構(gòu)造函數(shù)(偽構(gòu)造函數(shù))

考慮過,創(chuàng)建一個隱藏的tr,基于此tr執(zhí)行創(chuàng)建操作。為了不破壞HTML整體結(jié)構(gòu),決定通過js生成tr對象并append到頁面中。

為了在頁面加載完成后,再執(zhí)行dom操作,所以將<script>放在代碼下端</body>之前。

基于table中的tbody進(jìn)行增刪操作,可以先聲明此全局變量

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

創(chuàng)建對象,可以使用document.createElement方法。

以面向?qū)ο蟮姆绞竭M(jìn)行編程,先寫構(gòu)造函數(shù)(其實并不是標(biāo)準(zhǔn)的構(gòu)造函數(shù)格式),從最內(nèi)部的元素開始。

td中可能會有text和button等表單元素,所以先創(chuàng)建一個 input 的構(gòu)造函數(shù)function myInput(vId, vClass, vType, vValue, vParent){}

這里有一個兼容性問題,就是IE內(nèi)核不支持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對象的構(gòu)造函數(shù),大同小異,代碼如下

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()

構(gòu)造函數(shù)完成之后,完善createTr()方法。

預(yù)想的tr結(jié)構(gòu)為 序號,文本框,操作按鈕。

依次創(chuàng)建相關(guān)對象。序號列需要動態(tài)刷新,所以先設(shè)定class名稱,通過方法執(zhí)行排序操作。

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()

創(chuàng)建一個動態(tài)排序方法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()方法,網(wǎng)上找到了解決方案

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(){} 

可惜沒有實現(xiàn)。

修改后的代碼為

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;  } } 

除了排序外,還需其他操作,所以我們創(chuàng)建一個init()方法,集中管理reSequence()這些方法,在createTr()方法的結(jié)尾調(diào)用init()方法。

清空行方法clearTrs()

移除/銷毀某個dom對象,首先想到的是remove()方法,不幸的是,存在IE瀏覽器兼容問題,因此,采用了一個更簡便的方式,對dom對象執(zhí)行innerHTML="",代碼如下

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

IE8報錯,'未知的運行錯誤'。查了以下,因為ie8的table.innerHTML是只讀屬性,妹的!再改:

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

刪除行方法addBtnDelsListener()

接下來,給DELETE按鈕綁定刪除當(dāng)前行的方法。

為了解決兼容性問題,網(wǎng)上給出的方法是針對不同瀏覽器(IE、非IE)分別使用addEventListener、attachEvent方法,

我采用的是另一種解決方案:

obj.onclick = function(){};

匿名函數(shù)的方法體,吸取了上面clearTrs()方法的經(jīng)驗教訓(xùn),直接采用deleteRow(index)方法。

有一點需要注意thisTr.rowIndex獲取的行數(shù),比當(dāng)前行要大2,因為thead中還有兩行。所以當(dāng)前的索引數(shù)=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();   };  } } 

執(zhí)行完刪除操作后,通過reSequence()方法重新排序。

同時將addBtnDelsListener()方法加入到init()方法中。

復(fù)制行方法addBtnCpsListener()

再來看一下COPY按鈕,添加事件監(jiān)聽的方式同上。

如果innerHTML不是只讀的話,可以createElement一個tr元素 然后newTr.innerHTML=thisTr.innerHTML,

為了兼容性,必須做些改變。

其實可以將復(fù)制看做是新建,唯一的不同在于新建行的文本輸入框的內(nèi)容要等同于被復(fù)制行。

這就簡單了。我可以先調(diào)用createTr()方法,再將最后一個元素lastChild中的文本框的value等于被復(fù)制行。

思路有了,代碼如下:

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;   }  } } 

優(yōu)化修改

進(jìn)行一些優(yōu)化修改工作:

var elements = new Array();

修改為:var elements = [];

原因:數(shù)組用[]更好

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

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

外部新創(chuàng)建一個函數(shù)

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;

外部新創(chuàng)建一個函數(shù)

<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函數(shù)

修改為:

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;   } } 

原因:?:預(yù)期返回值應(yīng)該是一個變量or函數(shù),而不應(yīng)該是一個表達(dá)式操作。

有一點需要注意:js最佳實現(xiàn)經(jīng)常看到要使用===替換==。但是本示例中的==null,如果替換成===null會在ie8一下版本中出現(xiàn)問題。

完整代碼

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

還是想吐槽一下,如果不兼容IE10以下的版本,可以節(jié)省50%的代碼。如果使用jQuery,又可以節(jié)省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> 

以上就是本文的全部內(nèi)容,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,同時也希望多多支持VeVb武林網(wǎng)!


注:相關(guān)教程知識閱讀請移步到JavaScript/Ajax教程頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 宁夏| 莒南县| 永州市| 遂溪县| 门源| 新津县| 荥经县| 杨浦区| 黄浦区| 怀柔区| 巫溪县| 准格尔旗| 古交市| 毕节市| 曲水县| 望奎县| 清远市| 英超| 康定县| 淄博市| 若尔盖县| 桃园县| 西宁市| 定南县| 灵璧县| 蚌埠市| 绥中县| 洪洞县| 西城区| 丰顺县| 东宁县| 宝坻区| 东明县| 额尔古纳市| 菏泽市| 舟山市| 台州市| 平陆县| 新宾| 五原县| 广宗县|