【问题标题】:What is causing this unexpected Javascript error?是什么导致了这个意外的 Javascript 错误?
【发布时间】:2011-09-07 09:51:35
【问题描述】:

此代码旨在将样式“显示:无”添加到每个不具有“ShowThis”类或该类的后代的元素:

var x = document.getElementsByTagName('*');
for(var i = x.length; i--;){
    x[i].style.display = 'none';
    if((' '+x[i].className+' ').indexOf(' ShowThis ') >= 0){
        var y = x[i];
        while(y){
            if(y.nodeType === 1){
                console.log(y.style.cssText);    // Outputs: "display: none;"
                console.log(y.style.display);    // Outputs: "none"
                y.style.display = 'block';
                console.log(y.style.display);    // Outputs: "block"
                console.log(y.style.cssText);    // Outputs: "display: block;"

                // ERROR here:
                    // Outputs the elements HTML (Chrome Console),
                    // But the style attribute isn't changed
                    // EX. <div style="display: none;">...</div>
                console.log(y);
            }
            y = y.parentNode;
        }
    }
}

这是一个 JSFiddle:http://jsfiddle.net/Paulpro/wEq8X/

如果您注释掉 if(y.nodeType === 1){ 和匹配的 } (http://jsfiddle.net/Paulpro/wEq8X/1/),或者如果我将 if 语句更改为 if(y.nodeType)if(true),它工作正常我,因为程序流程正在进入该 if 语句(所有console.log 都已执行)。

我已尝试将 if 语句更改为 if(typeof y.style !== 'undefined'),但它的行为也不正确。 (完全一样的问题)

我需要测试 nodeType 或 style 以防止在尝试访问文档的 style 属性时出现错误,但是测试它们中的任何一个都会给我这种奇怪的行为。

我可以在 Chrome、Firefox 和 IE 中重现此内容。

【问题讨论】:

  • 当删除删除style.display = 'none'时,它应该设置为''(空字符串),因为有很多元素的默认显示属性不是block(@ 987654323@ 在 CSS 2.1 中有 16 个不同的值)。设置为空字符串允许元素采用其默认或继承的样式,而无需您明确地这样做。
  • 我已经更新了答案。您的代码取决于返回页面元素的顺序。如果在内部元素之后看到容器元素,并且容器没有“ShowThis”,那么它将不起作用。
  • @RobG 我不知道空字符串会将其重置为默认值。很方便,谢谢。
  • 哈哈——又更新了。我需要多睡觉什么的;我不知道我怎么错过了那个明显的细节。

标签: javascript html css dom


【解决方案1】:

您的代码将 包含 块设置为“显示:无”。之后,内部的&lt;div&gt;是“display:block”就没有关系了。

您转储元素的诊断技术存在缺陷。如果您使用 Chrome 调试器或 Firebug 之类的工具,您会看到“ShowThis”元素的“style”属性中确实有“display: block”。但是,它没有显示出来,因为它的所有父元素(包括&lt;body&gt; 标签)仍然是“display: none”。

edit 我认为问题可能源于页面元素出现在“getElementsByTagName()”结果中的顺序。如果您在子元素之后到达父元素,那么它们将被设置为“display: none”它们被设置为“display: block”之后。

再次编辑——确认。从“getElementsByTagName()”返回的元素以它们在 HTML 中出现的相反顺序出现。因此,您的代码在 outer 循环中看到的最后一个元素是“ShowThis”&lt;div&gt; 的容器 &lt;div&gt;

再次编辑哦,天哪,我明白了 - 你在倒退!杜尔。如果您继续通过节点列表,它应该可以工作。

【讨论】:

  • 感谢您的反对。有什么解释吗?我的陈述是准确的。
  • 它有while循环向上迭代并将所有祖先设置为'display:block;'。这不是问题。
  • 恐怕你弄错了,@PaulPRO。它显然不起作用。
  • 父元素确实有'display: none',但这就是错误。这段代码改变了它,console.log(y.style.display); 为每个祖先输出“块”(检查 Chrome 调试器),然后当我输出实际元素时它没有改变。
  • 完成后,父节点的样式不正确。我想我也知道为什么会这样。
【解决方案2】:

您的问题是,隐藏所有内容的外部循环将隐藏“showthis”节点的父节点,然后将其设置为 display='block'。如果你把隐藏和显示分成两步,效果很好。

var y, x = document.getElementsByTagName('*');
for(var i = 0, len = x.length; i < len; i++){
    x[i].style.display = 'none';
}
x = document.getElementsByClassName('ShowThis');
for(var i = 0, len = x.length; i < len; i++) {
    y = x[i];
    while(y){
        if(y.nodeType === 1){
            y.style.display = 'block';
        }
        y = y.parentNode;
    }
}

另外,为了记录,这种类型的东西是 jQuery 很棒的地方。

jQuery('*').hide();
jQuery('.ShowThis').show().parents().show();

【讨论】:

  • 我知道,我想把这个脚本传递给我的朋友,尽管它可以消除我们大学时间表周围的垃圾,使其更适合打印,哈哈。 Universities 网站不使用 jQuery。
  • 谢谢你顺便说一句,这个解决方案也有效,但我只需要向前迭代来修复它。我通过 getElementsByTagName 的结果集向后迭代。
  • 不错。您应该考虑将其设为 GreaseMonkey 脚本。如果以另一种方式迭代有效,那就太好了。我不能保证这将适用于所有浏览器。这完全取决于 getElementsByTagName 的顺序。不确定订单是否属于规格。
猜你喜欢
  • 2016-08-09
  • 2011-08-13
  • 2012-10-06
  • 2012-09-21
  • 2010-10-12
  • 2013-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多