会社のインターンさんからテーブルの追加と削除について質問されましたが、jQueryを使って実装するのはとても簡単でした。また、jQuery を使用せずに js のみを使用して実装する方法についても尋ねました。
このような状況に直面したとき、私の通常のアプローチは「理解できないが、サポートする」です。
私は jQuery をよく使ってきましたが、人々はあまりにも怠け者ですが、この操作を実装するのに依然として js を使用していましたが、問題は IE との互換性にあると思います。 。 。
コードを見つけるだけの場合は、分析プロセスをスキップできます。完全なコードは記事の最後に添付されています。
以下はコーディングプロセスです:
HTML構造コード
いくつかの簡単なスタイルが追加された基本的なテーブル構造、作成、クリア、および1つの予約に対応する3つのボタン。
<!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>
Constructor(擬似コンストラクター)
検討すると、隠しtrを作成し、このtrを元に作成操作を行います。 HTML の全体的な構造を壊さないようにするために、js を通じて tr オブジェクトを生成し、ページに追加することにしました。
ページが読み込まれた後に DOM 操作を実行するには、コードの下部の
の前に <script> を配置します。 </p><p>テーブル内の tbody に基づいて追加および削除操作を実行するには、最初にこのグローバル変数を宣言します</p><p>var vTbody = document.getElementById('main-table').getElementsByTagName('tbody')[0];オブジェクトを作成するには、document.createElement メソッドを使用できます。 </p><p>オブジェクト指向の方法でプログラムする場合は、最初にコンストラクターを記述します (実際には、これは標準のコンストラクター形式ではありません)。最も内側の要素から始めます。 </p><p> td にはテキストやボタンなどのフォーム要素が存在する可能性があるため、まず入力コンストラクター関数 myInput(vId, vClass, vType, vValue, vParent) を作成します。{}</p><p> ここには互換性の問題、つまり IE が存在します。カーネルは setAttribute(class, value) をサポートしていません。setAttribute(className, value) を使用する必要があるため、互換性の問題を解決するには、FF、Chrome では </p><p>setAttribute(class, value) を使用できます。 IE の setAttribute(className, value) </p>ここでは別のメソッドが使用されています。className、コードは次のとおりです: <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">ログイン後にコピー</div></div></p>次に、同様の td オブジェクトと tr オブジェクトのコンストラクターがあります。コードは次のとおりです。 <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">ログイン後にコピー</div></div></p>新しい行メソッドcreateTr()<p></p>コンストラクターが完了したら、createTr()メソッドを完成させます。 <p></p>想定されるtr構造はシリアル番号、テキストボックス、操作ボタンです。 <p></p>関連するオブジェクトを順番に作成します。シリアル番号列は動的に更新する必要があるため、最初にクラス名を設定し、メソッドを通じて並べ替え操作を実行します。 <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">ログイン後にコピー</div></div></p>ソートメソッド reSequence()<p></p> 動的ソートメソッド reSequence() を作成します。 Firefox では互換性の問題があるため、innerHTML が使用されます。コードは次のとおりです<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">ログイン後にコピー</div></div></p>IE8以下ではgetElementsByClassName()メソッドがサポートされていません<p>オンラインで解決策を見つけました</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">ログイン後にコピー</div></div><p>このメソッドをObjectやHTMLTableSectionElementのプロトタイプに追加してみました。 </p><p>HTMLTableSectionElement.prototype.getElementsByClassName = function(){} </p><p>残念ながら実装されていません。 </p><p>修正したコードは</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">ログイン後にコピー</div></div>です<p>ソート以外にも他の操作が必要なので、reSequence()メソッドを一元管理するinit()メソッドを作成し、createTr()の最後でinit()メソッドを呼び出します。 ) 方法。 </p><p> ClearTrs()</p><p> DOM オブジェクトを削除/破棄するには、remove() メソッドが最初に思い浮かびますが、残念ながら、IE ブラウザの互換性の問題があるため、より簡単な方法が採用されています。 innerHTML="" で、コードは次のとおりです </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">ログイン後にコピー</div></div><p>IE8 は「不明な実行エラー」というエラーを報告します。 IE8 の table.innerHTML は読み取り専用属性なので、次のことを確認しました。再度変更します: </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">ログイン後にコピー</div></div><p>行の削除メソッド addBtnDelsListener()</p><p> 次に、現在の行を削除するメソッドを DELETE ボタンにバインドします。 </p><p>互換性の問題を解決するために、インターネットで提供されている方法は、異なるブラウザー (IE、非 IE) にそれぞれ addEventListener メソッドとattachEvent メソッドを使用することです。</p><p>私は別の解決策を使用します: </p><p>obj.onclick = function。 (){};</p><p>匿名関数のメソッド本体は、上記の clearTrs() メソッドから経験と教訓を学び、deleteRow(index) メソッドを直接使用します。 </p><p> 注意すべき点は、先頭にはあと 2 行あるため、thisTr.rowIndex によって取得される行数は現在の行より 2 多いことです。したがって、現在のインデックス番号 = thisTr.rowIndex-vThead.rows.length</p><p> コードは次のとおりです:</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">ログイン後にコピー</div></div><p> 削除操作を実行した後、reSequence() メソッドを通じて並べ替えます。 </p><p>また、addBtnDelsListener() メソッドを init() メソッドに追加します。 </p><p>コピーラインメソッドaddBtnCpsListener()</p><p>COPYボタンをもう一度見てみましょう。イベントリスナーを追加する方法は上記と同じです。 </p><p> innerHTML が読み取り専用でない場合は、createElement と tr 要素を組み合わせて newTr.innerHTML=thisTr.innerHTML にすることができます。 </p><p> 互換性を確保するために、いくつかの変更を加える必要があります。 </p><p>実際、コピーは新しい行を作成することとみなすことができます。唯一の違いは、新しい行のテキスト入力ボックスの内容がコピーされた行と同じである必要があることです。 </p><p>それは簡単です。最初に createTr() メソッドを呼び出してから、最後の要素 lastChild のテキスト ボックスの値をコピーされた行と等しくなるように設定します。 </p><p>アイデアはそこにあり、コードは次のとおりです: </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">ログイン後にコピー</div></div><p>最適化の変更</p><p> いくつかの最適化の変更を実行します: </p><p>var elements = new Array();</p><p>次のように変更します: var elements = [];</p><p>Reason : 配列は addBtnDelsListener メソッドで [ ]Better</p><p>Place vBtnDels[i].onclick = function() {</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">ログイン後にコピー</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">ログイン後にコピー</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">ログイン後にコピー</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>