在firefox下忽略whitespace节点遍历dom

By | December 15, 2008

IE和FF的whitespace节点处理是不一样的,IE会忽略dom中的whitespace,而ff不会,所以以下代码在IE和FF下执行效果是不一样的:

<div id="container">
    <div id="main">
        <div id="sub1">
            hello sub 1.
        </div>
        <div id="sub2">
            hello sub 2.
        </div>
    </div>
</div>
<script type="text/javascript">
    function test(){
        alert( $('container').firstChild.firstChild.nextSibling.id );
    }
    test();
</script> 

为了使两个浏览器运行效果一致,则需要把所有dom中的whitespace节点去掉,可以这样写:

/*
*
*remove whitespace for the dom, so that document.documentElement.firstChild.nextSibling.firstChild can work.
*
*/
_rdc.cleanWhitespace = function( element ) {
    // If no element is provided, do the whole HTML document
    element = element || document;

    for (var i = 0; i < element.childNodes.length; i++) {
        var node = element.childNodes[i];
        if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
            element.removeChild(node);
    }

    for (var i = 0; i < element.childNodes.length; i++)
        _rdc.cleanWhitespace( element.childNodes[i] );
}  

然后,在dom trace之前调用一下,递归地把document下面所有whitespace去掉:

<div id="container">
    <div id="main">
        <div id="sub1">
            hello sub 1.
        </div>
        <div id="sub2">
            hello sub 2.
        </div>
    </div>
</div>
<script type="text/javascript">
    function test(){
        _rdc.cleanWhitespace();
        alert( $('container').firstChild.firstChild.nextSibling.id );
    }
    test();
</script>  

两个浏览器执行的效果就一样了。

更新:

此方法可能效率会低一点,因为要遍历所有dom节点。所以建议写类似几个方法:

/*
*
* get the previous element ignore whitespace
*
*/
_rdc.prev = function( elem ) {
    do {
        elem = elem.previousSibling;
    } while ( elem && elem.nodeType != 1 );

    return elem;
}

/**//*
*
* get the next element ignore whitespace
*
*/
_rdc.next = function( elem ) {
    do {
        elem = elem.nextSibling;
    } while ( elem && elem.nodeType != 1 );

    return elem;
}

/**//*
*
* get the first child element ignore whitespace
*
*/
_rdc.first = function( elem ) {
    elem = elem.firstChild;
    return elem && elem.nodeType != 1 ? _rdc.next ( elem ) : elem;
}

/**//*
*
* get the last child element ignore whitespace
*
*/
_rdc.last = function( elem ) {
    elem = elem.lastChild;
    return elem && elem.nodeType != 1 ? _rdc.prev ( elem ) : elem;
}

/**//*
*
* get the parent element ignore whitespace
*
*/
_rdc.parent = function( elem, num ) {
    num = num || 1;
    for ( var i = 0; i < num; i++ )
        if ( elem != null )
            elem = elem.parentNode;
    return elem;
}  

使用方法:

alert( _rdc.next( _rdc.first( _rdc.first(  $('container') ) ) ).id );