JavaScript - 使用childNodes遍历HTML DOM会导致非IE浏览器出错

时间:2009-05-28 11:49:50

标签: javascript html dom

我在浏览器中呈现了下表。它是从服务器端生成的。

<table id="tblQuestions" class="tblQuestionsContainer" border="0">
    <tr>
        <td id="1" class="tdQuestion">Are u an indian citizen ?</td>
    </tr><tr>
        <td><table id="answer-1" border="0">
            <tr>
                <td><input id="answer-1_0" type="radio" name="answer-1" value="1" /><label for="answer-1_0">Yes</label></td><td><input id="answer-1_1" type="radio" name="answer-1" value="0" /><label for="answer-1_1">No</label></td>
            </tr>
        </table></td>
    </tr><tr>
        <td id="2" class="tdQuestion">Do you have a passport ?</td>
    </tr><tr>
        <td><table id="answer-2" border="0">
            <tr>
                <td><input id="answer-2_0" type="radio" name="answer-2" value="1" /><label for="answer-2_0">Yes</label></td><td><input id="answer-2_1" type="radio" name="answer-2" value="0" /><label for="answer-2_1">No</label></td>
            </tr>
        </table></td>
    </tr>
</table>

现在我在JavaScript中使用以下代码来验证单选按钮的已检查状态。

 var tblQuestionBoard=document.getElementById("tblQuestions");
  tblAnswer = tblQuestionBoard.rows[1].childNodes[0].childNodes[0]

现在tblAnswer应该是一个具有id为“answer-1”的表的对象

在IE中,我得到了它。但是在Mozilla和其他浏览器中,我认为它是未定义的。

如何解决这个问题?

1 个答案:

答案 0 :(得分:9)

这是因为您正在使用childNodes,并且DOM中的空格被Firefox等视为文本节点。但不是IE

请参阅this answer了解

我的建议

1.设置一些包装函数,忽略除1(ELEMENT_NODE)之外的任何nodeType来进行DOM遍历。像

这样的东西
function child(elem, index) {
    // if index is not supplied, default is 1 
    // you might be more comfortable making this 0-based
    // in which case change i initial assignment value to 0 too
    index = index || 1; 
    // get first child element node of elem
    elem = (elem.firstChild && elem.firstChild.nodeType != 1) ?
               next(elem.firstChild) :
               elem.firstChild; 
    // use the index to move to nth-child element node             
    for(var i=1; i < index;i++) {
        (function() {     
            return elem = next(elem);         
        })();        
    }
    return elem;
}

function next(elem) {
    do {
        elem = elem.nextSibling;
    } while (elem && elem.nodeType != 1);
return elem;                
}

并像这样使用 - Working Demo - (答案底部的代码供参考)

<table id="myTable">
    <thead>
        ...
    </thead>
    <tbody>
        ...
    </tbody>
</table>

<script type="text/javascript">
    child(document.getElementById('myTable'), 2); // will get the tbody
</script>

2.使用getElementbyId()getElementsByTagName()getElementsByName(),而不是依赖于DOM中的位置

3.使用一个抽象浏览器差异的JavaScript库(强烈推荐jQuery

演示代码

<!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" xml:lang="en" lang="en">
<head>
<script type="text/javascript">
    window.onload = function() {    
       document.getElementById('getCellContents').onclick = getCellContents;    
    }

    function child(elem, index) {
        index = index || 1; 
        elem = (elem.firstChild && elem.firstChild.nodeType != 1) ?
                   next(elem.firstChild) :
                   elem.firstChild;            
        for(var i=1; i < index;i++) {
            (function() {    
                return elem = next(elem);         
            })();        
        }
        return elem;
    }

    function next(elem) {
        do {
            elem = elem.nextSibling;
        } while (elem && elem.nodeType != 1);
    return elem;                
    }

    function getCellContents() {
        var row = parseInt(document.getElementById('row').value, 10);
        var column = parseInt(document.getElementById('column').value, 10);
        var result;
        var color;
        var table = document.getElementById('table');
        var cells = table.getElementsByTagName('td');
        for (var i= 0; i < cells.length; i++) {
            (function() {
                cells[i].bgColor = '#ffffff';
            })();
        }

        if (row && column) {
            var tbody = child(table , 2);
            var selectedRow = (row <= tbody.getElementsByTagName("tr").length)? child(tbody, row): null;
            var selectedCell = (selectedRow && column <= selectedRow.getElementsByTagName("td").length)? child(selectedRow, column): null;  

            if (selectedRow && selectedCell) {
                selectedCell.bgColor = '#00ff00';
                result = selectedCell.innerHTML;
                color = '#b7b7b7';
            }
            else {
                result = 'Cell does not exist';
                color = '#ff0000';
            }                                           
        }
        else {
            result = 'You must provide numeric arguments for Row and Column Number';
            color = '#ff0000';
        }       
        var results = document.getElementById('results');
        results.innerHTML = result;
        results.style.color = color;
    }


</script>
<title>DOM Traversal</title>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<style type="text/css">
body {
    font-family: Verdana, Helvetica, Arial;
    font-size: 0.8em;
}
h2 {
    text-align:center;
}
table { 
    border: 1px solid #000;
    border-collapse: collapse;
}   
th, td { 
    border: 1px solid #000; 
    padding: 2px; 
}
fieldset {
    border: 0;
}
label {
    display: block;
    width: 120px;
    text-align: right;
    float: left;
    padding-right: 10px;
    margin: 5px 0;
}
input {
    margin: 5px 0;
}

input.text {
    padding: 0 0 0 3px;
    width: 172px;
}

input.button {
    margin: 15px 0 0 130px;
}
span {
    font-weight: bold;
    color: #b7b7b7;
}
</style>
</head>
<body>

<h2>Example to demonstrate use of JavaScript DOM traversing wrapper functions</h2>
<div style="margin: 0 auto; width: 600px;">
<fieldset>
    <label for="row">Row Number:</label><input id="row" class="text" type="text" /><br/>
    <label for="column">Column Number:</label><input id="column" class="text" type="text" /><br/>
    <input id="getCellContents" type="button" class="button" value="Get Cell Contents" />
</fieldset> 

<p>Results: <span id="results"></span></p>

  <table id="table">
  <thead>
    <tr>
            <th>Column 1</th>
            <th>Column 2</th>   
        <th>Column 3</th>
        <th>Column 4</th>
        <th>Column 5</th>   
    </tr>   
  </thead>
  <tbody>
      <tr>
        <td>Banana</td>
        <td>Apple</td>
        <td>Orange</td>
        <td>Pineapple</td>
        <td>Cranberry</td>
      </tr>
      <tr>
        <td>Monkey</td>
        <td>Giraffe</td>
        <td>Elephant</td>
        <td>Tiger</td>
        <td>Snake</td>
      </tr>
      <tr>
        <td>C#</td>
        <td>Java</td>
        <td>Python</td>
        <td>Ruby</td>
        <td>Haskell</td>
      </tr>
      <tr>
        <td>France</td>
        <td>Spain</td>
        <td>Italy</td>
        <td>Germany</td>
        <td>Netherlands</td>
      </tr>
  </tbody>
  </table>
<p style="font-weight:bold;">The Code:
<pre><code>
&lt;script type="text/javascript"&gt;
window.onload = function() {    
   document.getElementById('getCellContents').onclick = getCellContents;    
}

function child(elem, index) {
    index = index || 1; 
    elem = (elem.firstChild && elem.firstChild.nodeType != 1) ?
               next(elem.firstChild) :
               elem.firstChild;                
    for(var i=1; i < index;i++) {
        (function() {   
            if(elem)  
            return elem = next(elem);         
        })();        
    }
    return elem;
}

function next(elem) {
    do {
        elem = elem.nextSibling;
    } while (elem && elem.nodeType != 1);
return elem;                
}

function getCellContents() {
    var row = parseInt(document.getElementById('row').value, 10);
    var column = parseInt(document.getElementById('column').value, 10);
    var result;
    var color;
    var table = document.getElementById('table');
    var cells = table.getElementsByTagName('td');
    for (var i= 0; i < cells.length; i++) {
        (function() {
            cells[i].bgColor = '#ffffff';
        })();
    }

    if (row && column) {
        var tbody = child(table , 2);
        var selectedRow = (row <= tbody.getElementsByTagName("tr").length)? 
                            child(tbody, row): null;
        var selectedCell = (selectedRow && column <= selectedRow.getElementsByTagName("td").length)? 
                                child(selectedRow, column): null;   

        if (selectedRow && selectedCell) {
            selectedCell.bgColor = '#00ff00';
            result = selectedCell.innerHTML;
            color = '#b7b7b7';
        }
        else {
            result = 'Cell does not exist';
            color = '#ff0000';
        }                                           
    }
    else {
        result = 'You must provide numeric arguments for Row and Column Number';
        color = '#ff0000';
    }       
    var results = document.getElementById('results');
    results.innerHTML = result;
    results.style.color = color;
}
&lt;/script&gt;
</code>
</pre>
</p>
  </div>
</body>
</html>