Le stagiaire de l'entreprise m'a posé des questions sur l'ajout et la suppression de tables, et c'était très simple à mettre en œuvre avec jQuery. Il m'a également demandé comment l'implémenter sans utiliser jQuery et uniquement en utilisant js.
Face à cette situation, mon approche habituelle est « ne pas comprendre, mais soutenir ».
J'ai beaucoup utilisé jQuery et les gens sont trop paresseux, mais j'ai quand même utilisé js pour implémenter cette opération, je pense que la difficulté réside dans la compatibilité avec IE. . .
Si vous souhaitez simplement rechercher le code, vous pouvez ignorer le processus d'analyse. Le code complet est joint au bas de l'article.
Voici le processus de codage :
Code de structure HTML
Une structure de table de base avec quelques styles simples ajoutés. Trois boutons correspondent à créer, effacer et réservé.
<!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>
Constructeur (pseudo constructeur)
Considéré, créez un tr caché et effectuez l'opération de création basée sur ce tr. Afin de ne pas détruire la structure globale du HTML, il a été décidé de générer l'objet tr via js et de l'ajouter à la page.
Afin d'effectuer des opérations DOM après le chargement de la page, placez <script> en bas du code avant </body>. </p><p>Pour effectuer des opérations d'ajout et de suppression basées sur le corps du tableau, vous pouvez d'abord déclarer cette variable globale </p><p>var vTbody = document.getElementById('main-table').getElementsByTagName('tbody ')[0] ; </p><p>Pour créer un objet, vous pouvez utiliser la méthode document.createElement. </p><p>Programmez de manière orientée objet, écrivez d'abord le constructeur (en fait ce n'est pas un format de constructeur standard), en commençant par l'élément le plus interne. </p><p>Il peut y avoir des éléments de formulaire tels que du texte et un bouton dans td, alors créez d'abord une fonction de constructeur d'entrée myInput(vId, vClass, vType, vValue, vParent){}</p><p>En voici un. Le problème de compatibilité est que le noyau IE ne prend pas en charge setAttribute(class, value) et doit utiliser setAttribute(className, value). Par conséquent, afin de résoudre le problème de compatibilité, vous pouvez utiliser </p><p>setAttribute(class,). value) pour FF et Chrome .</p><p>setAttribute(className, value) pour IE</p><p>Voici une autre façon .className, le code est le suivant : </p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false">function myInput(vId, vClass, vType, vValue, vParent) { var vInput = document.createElement(&#39;input&#39;); if(vId) { vInput.setAttribute(&#39;id&#39;, vId); } vInput.setAttribute(&#39;type&#39;, vType); vInput.setAttribute(&#39;value&#39;, vValue); vInput.className = vClass; if(vParent) { vParent.appendChild(vInput); } }</pre><div class="contentsignin">Copier après la connexion</div></div><p> Puis td object et tr Le constructeur de l'objet est similaire, le code est le suivant </p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false">function myTd(vId, vClass, vChild, vParent) { var vTd = document.createElement(&#39;td&#39;); if(vId){ vTd.setAttribute(&#39;id&#39;, 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(&#39;tr&#39;); if(vId){ vTr.setAttribute(&#39;id&#39;, vId); } vTr.className = vClass; if(vChild) { vTr.appendChild(vChild); } if(vParent) { vParent.appendChild(vTr); } return vTr; }</pre><div class="contentsignin">Copier après la connexion</div></div><p>Nouvelle méthode de ligne createTr()</p><p>Une fois le constructeur terminé, améliorez le createTr() méthode. </p><p>La structure tr attendue est le numéro de série, la zone de texte et le bouton d'opération. </p><p>Créez des objets associés en séquence. La colonne du numéro de série doit être actualisée dynamiquement, alors définissez d'abord le nom de la classe et effectuez l'opération de tri via la méthode. </p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false">function createTr() { var vTr = new myTr(null, null, null, vTbody); //序列td var vTdSeq = new myTd(null, &#39;seq&#39;, null, vTr); //文本框td var vTdText = new myTd(null, null, null, vTr); var vInputText = new myInput(null, &#39;td-inp-txt&#39;, &#39;text&#39;, &#39;&#39;, vTdText); //操作按钮td var vTdBtn = new myTd(null, null, null, vTr); var vInputBtnCp = new myInput(null, &#39;td-inp-btn-cp&#39;, &#39;button&#39;, &#39;COPY&#39;, vTdBtn); var vInputBtnDel = new myInput(null, &#39;td-inp-btn-del&#39;, &#39;button&#39;, &#39;DELETE&#39;, vTdBtn); }</pre><div class="contentsignin">Copier après la connexion</div></div><p>Méthode de tri reSequence()</p><p>Créer une méthode de tri dynamique reSequence() Il y a un problème de compatibilité innerText n'a aucun effet sous Firefox, donc innerHTML est utilisé. Le code est le suivant </p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:html;toolbar:false">function reSequence() { var vObj = vTbody.getElementsByClassName(&#39;seq&#39;); for (var i=0, len=vObj.length; i<len; i++) { vObj[i].innerHTML = i+1; } }</pre><div class="contentsignin">Copier après la connexion</div></div><p>Il y a un problème de compatibilité. IE8 et les versions inférieures ne prennent pas en charge la méthode getElementsByClassName(). J'ai trouvé une solution en ligne </p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;">if(!document.getElementsByClassName){ document.getElementsByClassName = function(className, element){ var children = (element || document).getElementsByTagName(&#39;*&#39;); var elements = new Array(); for (var i=0; i<children.length; i++){ var child = children[i]; var classNames = child.className.split(&#39; &#39;); for (var j=0; j<classNames.length; j++){ if (classNames[j] == className){ elements.push(child); break; } } } return elements; }; }</pre><div class="contentsignin">Copier après la connexion</div></div><p>J'essaie d'utiliser le. prototype d'Object ou HTMLTableSectionElement Ajoutez cette méthode, telle que </p><p>HTMLTableSectionElement.prototype.getElementsByClassName = function(){} </p><p> Malheureusement, elle n'est pas implémentée. </p><p>Le code modifié est </p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false">function reSequence() { var vObj = vTbody.getElementsByClassName == null?document.getElementsByClassName(&#39;seq&#39;, vTbody):vTbody.getElementsByClassName(&#39;seq&#39;); for (var i=0, len=vObj.length; i<len; i++) { vObj[i].innerHTML = i+1; } }</pre><div class="contentsignin">Copier après la connexion</div></div><p>En plus du tri, d'autres opérations sont nécessaires, nous créons donc une méthode init() pour gérer de manière centralisée les méthodes reSequence(), dans createTr() La méthode init() est appelée à la fin de la méthode. </p><p>Effacer la méthode de ligne vide clearTrs()</p><p>Pour supprimer/détruire un objet DOM, la première chose qui vient à l'esprit est la méthode Remove(). Malheureusement, il existe un problème de compatibilité avec le navigateur IE. , utilisez donc Un moyen plus simple consiste à exécuter innerHTML="" sur l'objet dom. Le code est le suivant </p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false">function clearTrs() { vTbody.innerHTML = &#39;&#39;; }</pre><div class="contentsignin">Copier après la connexion</div></div><p>IE8 signale une erreur, 'Erreur d'exécution inconnue'. J'ai vérifié ce qui suit, car le table.innerHTML d'IE8 est un attribut en lecture seule, bon sang ! Changez à nouveau : </p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false">function clearTrs() { while(vTbody.rows.length >0) { vTbody.deleteRow(); } }</pre><div class="contentsignin">Copier après la connexion</div></div><p>Méthode de suppression de ligne addBtnDelsListener()</p><p>Ensuite, liez la méthode de suppression de la ligne actuelle au bouton SUPPRIMER. </p><p>Afin de résoudre le problème de compatibilité, la méthode proposée sur Internet consiste à utiliser respectivement les méthodes addEventListener et attachEvent pour différents navigateurs (IE, non-IE </p><p>J'utilise une autre solution). :</p><p>obj.onclick = function(){};</p><p>Le corps de la méthode de la fonction anonyme a tiré l'expérience et les leçons de la méthode clearTrs() ci-dessus et utilise directement le deleteRow(index ) méthode. </p><p>Une chose à noter est que le nombre de lignes obtenues par thisTr.rowIndex est 2 supérieur à la ligne actuelle, car il y a deux lignes supplémentaires dans l'en-tête. Donc le nombre actuel d'index = thisTr.rowIndex-vThead.rows.length</p><p>Le code est le suivant :</p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false">function addBtnDelsListener() { var vBtnDels = vTbody.getElementsByClassName == null?document.getElementsByClassName(&#39;td-inp-btn-del&#39;, vTbody):vTbody.getElementsByClassName(&#39;td-inp-btn-del&#39;); 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(&#39;thead&#39;)[0].rows.length); reSequence(); }; } }</pre><div class="contentsignin">Copier après la connexion</div></div><p>Après avoir effectué l'opération de suppression, réorganisez via la méthode reSequence() . </p><p>En même temps, ajoutez la méthode addBtnDelsListener() à la méthode init(). </p><p>Méthode de copie de ligne addBtnCpsListener()</p><p>Regardez à nouveau le bouton COPIER. La méthode d'ajout d'écouteurs d'événements est la même que ci-dessus. </p><p>Si innerHTML n'est pas en lecture seule, vous pouvez createElement un élément tr puis newTr.innerHTML=thisTr.innerHTML, </p><p>Pour des raisons de compatibilité, certaines modifications doivent être apportées. </p><p>En fait, copier peut être considéré comme en créer une nouvelle. La seule différence est que le contenu de la zone de saisie de texte de la nouvelle ligne doit être égal à la ligne copiée. </p><p>C'est facile. Je peux d'abord appeler la méthode createTr(), puis définir la valeur de la zone de texte dans le dernier élément lastChild pour qu'elle soit égale à la ligne copiée. </p><p>J'ai l'idée, le code est le suivant : </p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false">function addBtnCpsListener() { var vBtnCps = vTbody.getElementsByClassName == null?document.getElementsByClassName(&#39;td-inp-btn-cp&#39;, vTbody):vTbody.getElementsByClassName(&#39;td-inp-btn-cp&#39;); 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(&#39;td-inp-txt&#39;, vNewTr)[0].value = document.getElementsByClassName(&#39;td-inp-txt&#39;, vTr)[0].value:vNewTr.getElementsByClassName(&#39;td-inp-txt&#39;)[0].value = vTr.getElementsByClassName(&#39;td-inp-txt&#39;)[0].value; } } }</pre><div class="contentsignin">Copier après la connexion</div></div><p>Optimisation et modifications</p><p>Effectuer quelques optimisations et modifications : </p><p>var elements = new Array(); </p><p> modifié en : var elements = [];</p><p> Raison : Il est préférable d'utiliser [] pour les tableaux </p><p> Changer vBtnDels[i].onclick = function() dans la méthode addBtnDelsListener {</p><p>修改为:vBtnDels[i].onclick = delTr;</p><p>外部新创建一个函数</p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false">function delTr() { var vTr = this.parentElement.parentElement; vTbody.deleteRow(vTr.rowIndex-vTbody.parentNode.getElementsByTagName(&#39;thead&#39;)[0].rows.length); reSequence(); }</pre><div class="contentsignin">Copier après la connexion</div></div><p>原因:Don't make functions within a loop.</p><p>同理,将addBtnCpsListener中的vBtnCps[i].onclick = function() {</p><p>修改为:vBtnCps[i].onclick = copyTr;</p><p>外部新创建一个函数</p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false"><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(&#39;td-inp-txt&#39;, vNewTr)[0].value = document.getElementsByClassName(&#39;td-inp-txt&#39;, vTr)[0].value: vNewTr.getElementsByClassName(&#39;td-inp-txt&#39;)[0].value = vTr.getElementsByClassName(&#39;td-inp-txt&#39;)[0].value; }</pre> <pre class="brush:php;toolbar:false"></pre> <pre class="brush:php;toolbar:false"></pre></pre><div class="contentsignin">Copier après la connexion</div></div><p>将copyTr()方法中的?:格式修改为if else函数。</p><p>修改为:</p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false">function copyTr() { createTr(); var vNewTr = vTbody.lastChild; var vTr = this.parentElement.parentElement; if(vNewTr.getElementsByClassName) { vNewTr.getElementsByClassName(&#39;td-inp-txt&#39;)[0].value = vTr.getElementsByClassName(&#39;td-inp-txt&#39;)[0].value; } else { document.getElementsByClassName(&#39;td-inp-txt&#39;, vNewTr)[0].value = document.getElementsByClassName(&#39;td-inp-txt&#39;, vTr)[0].value; } }</pre><div class="contentsignin">Copier après la connexion</div></div><p>原因:?:预期返回值应该是一个变量or函数,而不应该是一个表达式操作。</p><p>有一点需要注意:js最佳实现经常看到要使用===替换==。但是本示例中的==null,如果替换成===null会在ie8一下版本中出现问题。</p><p>完整代码</p><p>至此,一个完全基于原生JavaScript,并且兼容至IE6的table增删完成了。</p><p>还是想吐槽一下,如果不兼容IE10以下的版本,可以节省50%的代码。如果使用jQuery,又可以节省50%的代码。对于实用主义的我而言,这一过程备受煎熬。不过还是从中有所收益的(违心。。)</p><p>以下为完整代码:</p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:html;toolbar:false"><!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(&#39;thead&#39;)[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>