【问题标题】:JavaScript scope issue in Opera?Opera 中的 JavaScript 范围问题?
【发布时间】:2010-08-29 08:33:37
【问题描述】:

我有一个类似小部件的 HTML+JavaScript 块,人们可以将它复制/粘贴到他们的 HTML 页面中一次或多次。该块检查外部 JavaScript 文件是否已经在 DOM 中,如果没有则加载它,如下所示:

(function(){
  d = document;
  if (!d.getElementById('ex-scr')) {
    scr = d.createElement('script');
    scr.async = true;
    scr.id = 'ex-scr';
    scr.src = 'external.js';
    d.getElementsByTagName('head')[0].appendChild(scr)
  }
})();

外部 JavaScript 文件检查 HTML 页面中的小部件实例(使用 getElementsByClassName)并处理这些实例,有点像这样;

for (var i=0;i<document.getElementsByClassName('target').length;i++) {
 document.getElementsByClassName('target')[i].style.borderStyle="solid";
}

可以在 http://futtta.be/opera_enigma.html 上找到一个工作示例。

这在 Firefox (3.6 & 4b)、Chrome (5 & 6) 和 Safari 中完美运行,但在 Opera 中无法正常运行(使用最新版本 10.61 进行测试):无论有多少“小部件”(div class='target') 存在,Opera 只作用于第一个,因为显然 nodeList 只包含 1 个条目(长度是 1 而不是 2 或 3 或 ...)。

如果在小部件的 javascript 中我调用函数以使用 window.onload 加载外部脚本,问题就会消失,但我希望我的小部件尽快激活(不干扰页面的其余部分,因此异步的东西)。

所以我的问题;我的代码中是否存在 Firefox、Safari 和 Chrome 忽略的错误?这是Opera中的错误吗?如何让 Opera 正常运行?

【问题讨论】:

  • 嗯,首先应该是var d = document!请减少全局命名空间污染! :) 另外,请记住,每次访问 document.getElementsByClassName("target") 时,它都必须重新生成该列表。所以你应该做类似for (var i = 0, a = Array.prototype.slice.call(document.getElementsByClassName("target")), len = a.length; i &lt; len; i++) { a[i].style.borderStyle = "solid"; }
  • 谢谢,中肯的建议,我会记住的。

标签: javascript opera


【解决方案1】:

如果我在小部件的 javascript 中调用函数以使用 window.onload 加载外部脚本,问题就会消失

我认为这就是你的问题所在。在您的脚本文件中执行getElementsByClassName 时,尚不能保证DOM 完全存在。如果不等到DOMreadyloaded 事件,您将无法在此处创建可靠的行为。

【讨论】:

  • 这是有道理的,从这个意义上说,ff/chrome/safari 不介意我这样做甚至很奇怪 :)
  • @futtta 这可能取决于不同的 DOM 处理/渲染/优先级/优化方法。
  • 是的,我会尝试用 domready 做一些事情(特定于歌剧),谢谢!
  • @futtta 不客气,但我不会在任何浏览器中信任它。你永远不会确定你会得到什么结果,例如。在较慢的机器上。我会在所有浏览器中使用 DOMReady。
【解决方案2】:

您可能在浏览器之间遇到了一个小的时间差异:如果您通过 DOM 将 SCRIPT 添加到文档的头部,Opera 当前将等待脚本执行后再解析文档的其余部分。这是我在这里写的第三个问题: http://my.opera.com/hallvors/blog/2009/03/07/websites-playing-timing-roulette

其他主要浏览器在等待外部脚本时会继续解析。当外部脚本进入时,它们将运行外部脚本,这随机(取决于缓存、文档大小、连接速度等)可能会在您想要操作的所有元素都在时运行它DOM。但是,我几乎可以保证,在您知道解析完整标记之前尝试在 DOM 中查找某种类型的所有元素会导致任何浏览器中的某些用户出现问题 - 您在做什么对小的网络故障、连接速度差异、CPU 功率以及所有其他影响加载和解析网页时的时间的小差异过于敏感。

浏览器会为您提供页面已准备好编写脚本的两个信号:DOMContentLoaded 事件和 onload。如果您需要从文档或其元素中读取尺寸,您可能需要等到所有图像和 CSS 都加载完毕(即等待 onload 事件),否则您可以使用 DOMContentLoaded。 jQuery 为您提供了 $(document).ready() 来抽象出浏览器支持的“DOM 已准备就绪”信号的差异,其他框架可能有等价物。

【讨论】:

  • (顺便说一句,Opera 将尝试在这一点上与其他浏览器对齐时间,但需要注意的是“何时加载外部脚本”是并将仍然是一个随机因素。)
  • 基于此和 pekka 的 cmets,我已经在重写我的脚本以等待 domcontentloaded。关于 Opera 处理动态添加的脚本的方式;如果它等待脚本加载、解析和执行,这意味着目前无法在 Opera 中进行异步脚本加载(例如 google 使用他们的分析代码)?
  • 这不是不可能的,只要你记住在解析时,异步脚本可能看不到完整的 DOM,它就可以正常工作。如果您在 DOMContentLoaded 事件中或之后将这些脚本添加到 DOM,则从 DOM 中读取不会有任何问题。
猜你喜欢
  • 2010-09-24
  • 2011-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-18
  • 1970-01-01
  • 2014-10-24
相关资源
最近更新 更多