【问题标题】:Javascript not always working in Chrome Extension, when should I run it?Javascript 并不总是在 Chrome 扩展程序中运行,我应该什么时候运行它?
【发布时间】:2012-12-16 06:28:51
【问题描述】:

我有一个 Chrome 扩展程序,它将 CSS 和 Javascript 都注入到页面中,虽然 CSS 总是被注入,但 Javascript 仅在某些时候有效,而在其他时候无效。通过不工作,我假设它在它必须处理的东西存在之前运行。

Javascript 只是使用insertBeforediv 移动到另一个上方,但这并不总是发生,我认为这是因为它正在加载。

我的清单目前是:

{
  ...
  "content_scripts": [{
    "matches": [ "*://example.com/*" ],
     "js": [
        "js/jquery-1.8.3.min.js", "js/myjavascript.js"
      ],
      "run_at": "document_end",
      "css": [
        "css/mycss.css"
      ]
  }]
} 

我目前将run_at 设置为document_end,因为它似乎运行得更顺畅(当它工作时),所以我认为这就是需要更改的地方。

如果有人有任何建议,我们将不胜感激。

编辑:添加了关于此问题答案的后续问题here,我觉得如果我将其添加到此问题中可能对其他人有用。

【问题讨论】:

  • 不能用jquery load$(window).load(function(){ //Script });所以页面加载的时候会运行脚本的内容。
  • 他在注入jQuery,他可以使用$.ready我打赌
  • 这两种方法都有效,但速度明显变慢(页面正在加载,然后您可以看到 div 移动),这是我希望避免的。

标签: javascript google-chrome google-chrome-extension content-script


【解决方案1】:

如果代码并非始终有效,则表明元素正在由页面的 javascript 创建/加载。因此,您需要使用标准的 AJAX 感知技术来移动该 div。

这些技术是:计时器、突变观察者、突变事件和拦截 AJAX XHR(如果适用)。这些都在其他 Stack Overflow 问题中讨论过,但是: 不推荐使用突变事件/错误;拦截 XHR 变得混乱,可能不适用于这里;突变观察者可能会变得复杂。

我建议下载 the waitForKeyElements() utility 并将其添加到您的清单中。

那么移动<div>的代码就变成了:

waitForKeyElements (
    "jQuery selector for div(s) you want to move",
    moveSelectDivs
);
function moveSelectDivs (jNode) {
    jNode.insertBefore ("APPROPRIATE JQUERY SELECTOR");
}


将清单设置为run at document_end。这等价于DOMContentLoaded -- 这是$(document).ready() 触发的时间。默认的run_at 触发得太晚且时间不可预测。 run_at document_start 不会有任何好处,因为:计时器,突变观察者等都不会在 DOMContentLoaded 事件之后触发 - 无论如何对于当前版本的 Chrome (其他浏览器没有相同限制)。



替代方法,用于最快的操作但较慢的网页:

关于:

(页面正在加载,然后您可以看到 div 移动),这是我希望避免的。

DOMContentLoaded 之前只有两种方法可以在 Chrome 中执行任何操作:

  1. 您可以设置mycss.css 隐藏div,直到您移动它。就性能而言,这可能是最具成本效益的方法。
  2. 或者,您可以覆盖document.createElement()。这将尽可能快地响应新元素(假设它是在 DOMContentLoaded 之前创建的),但它可能会显着降低整个页面的速度。

将内容脚本设置为在document_start 运行,并且必须注入覆盖代码。所以,脚本看起来像:

addJS_Node (null, null, scriptMain);

function scriptMain () {
    var _orig_createElement = document.createElement;

    document.createElement  = function (tag) {
        var element = _orig_createElement.call (document, tag);

        var movingNode      = document.querySelector ("MOVING DIV SELECTOR");
        if (movingNode) {
            var target      = document.querySelector ("TARGET DIV SELECTOR");
            if (target) {
                target.parentNode.insertBefore (movingNode, target);

                document.createElement = _orig_createElement;
            }
        }

        return element;
    };
}

function addJS_Node (text, s_URL, funcToRun) {
    var D                                   = document;
    var scriptNode                          = D.createElement ('script');
    scriptNode.type                         = "text/javascript";
    if (text)       scriptNode.textContent  = text;
    if (s_URL)      scriptNode.src          = s_URL;
    if (funcToRun)  scriptNode.textContent  = '(' + funcToRun.toString() + ')()';

    var targ = D.getElementsByTagName ('head')[0] || D.body || D.documentElement;
    targ.appendChild (scriptNode);
}


不要尝试为此使用 jQuery。

【讨论】:

  • 您的脚本(第一个选项)效果很好,但是它会导致将在具有相同选择器的小弹出窗口(在同一 URL 上)中加载的内容移动到其后面的页面上,而不是离开它在哪里。有什么想法可以解决这个问题吗? - 显然这在大多数页面上都不是问题,但弹出窗口可以加载到不包含选择器的页面上,然后插入到其后面的主页中。
  • 刚刚错过了编辑的 5 分钟标记:我使用了 true 参数,这解决了问题,但是当 URL 发生更改或出现某种情况时,需要重置“匹配”可能会失败。
  • 要做的事情是以下一项或多项:(a)使用清单排除弹出窗口,(b)调整传递给waitForKeyElements的选择器,(c)检查@987654341内的弹出窗口@。 ...我们需要更多信息才能更具体。如有必要,开始一个新问题并提供目标页面和弹出窗口的完整详细信息。最好包含指向目标页面的链接。
  • 我现在添加了一个新问题here,希望它足够清楚。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-18
  • 2015-03-30
  • 1970-01-01
  • 1970-01-01
  • 2012-04-16
  • 1970-01-01
相关资源
最近更新 更多