Javascript并不总是在Chrome扩展中运行,我应该在什么时候运行它? [英] Javascript not always working in Chrome Extension, when should I run it?

查看:103
本文介绍了Javascript并不总是在Chrome扩展中运行,我应该在什么时候运行它?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Chrome扩展程序,它将CSS和Javascript注入到页面中,而CSS总是被注入,而JavaScript只是有时候而不是其他的。通过不工作,我认为它运行之前,它必须处理的东西存在。



Javascript只是移动 div >另一个使用 insertBefore 但这并不总是发生,我认为这是因为何时加载。



我的清单目前是:

  {
。 ..
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 ,因为它似乎运行更平滑(当它工作时),所以我认为这是什么需要改变。



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



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

决方案

如果代码不总是工作,则该表明元件(一个或多个)被创建/页面的javascript加载。因此,您需要使用标准的支持AJAX的技术来移动该div。

这些技术是:定时器,变异观察者,变异事件和拦截AJAX XHR(如果适用)。这些都在其他堆栈溢出问题中讨论过,但是:突变事件已被弃用/错误;拦截XHR变得混乱,可能不适用于此;并且突变观察者可能变得复杂。



我推荐下载并添加 waitForKeyElements()实用程序到您的清单。

然后移动< div>

  waitForKeyElements(
jQuery选择器要移动的div(s)),
moveSelectDivs
);
function moveSelectDivs(jNode){
jNode.insertBefore(APPROPRIATE JQUERY SELECTOR);
}



<保持清单设置为运行于 document_end 。这相当于 DOMContentLoaded - 这是在 $(document).ready()时触发的。默认 run_at 在太晚和不可预知的时间点燃。 run_at document_start 不会有任何好处,因为:定时器,突变观察者等都不会触发 DOMContentLoaded 事件 - 对于Chrome的当前版本(其他浏览器没有相同的限制)。









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




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


在Chrome中使用 DOMContentLoaded 之前,只有两种方法可用:


  1. 您可以设置 mycss.css 来隐藏div,直到您移动它为止。这可能是性价比最高的方法。

  2. 或者,您可以覆盖 document.createElement()。这将尽可能快地响应新元素(假设它是在 DOMContentLoaded 之前创建的),但它可能会使整个页面减慢一个明显量。

将内容脚本设置为在 document_start 处运行,并且必须注入覆盖代码。因此,该脚本将如下所示:

  addJS_Node(null,null,scriptMain); 

函数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;
}
}

返回元素;
};
}

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。

I have a Chrome Extension which is injecting both CSS and Javascript into the page, and while the CSS is always being injected, the Javascript is only working sometimes and not others. By not working, I assume it's running before the stuff exists that it has to deal with.

The Javascript is simply moving a div above another using insertBefore but this isn't always happening, and I assume it's because of when it's loading.

My manifest is currently:

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

I have run_at set to document_end currently because it seemed to run smoother (when it does work), so I figure that's what needs to be changed.

If anybody has any suggestions, they're greatly appreciated.

EDIT: A follow-up question regarding the answer to this question was added here, I felt it may be useful for others if I added it to this question.

解决方案

If the code is not always working, then that suggests that the element(s) are being created/loaded by the page's javascript. So, you need to use standard AJAX-aware techniques to move that div.

The techniques are: timers, mutation observers, mutation events, and intercepting AJAX XHR (if applicable). These are all discussed in other Stack Overflow questions, but: mutation events are deprecated/buggy; intercepting XHR gets messy and may not apply here; and mutation observers can get complicated.

I'd recommend downloading and adding the waitForKeyElements() utility to your manifest.

Then the code to move that <div> becomes merely:

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


Keep your manifest set to run at document_end. This is equivalent to DOMContentLoaded -- which is when $(document).ready() fires. The default run_at fires too late and at unpredictable times. run_at document_start won't do any good, since: timers, mutation observers, etc. all will not fire until after the DOMContentLoaded event -- for current versions of Chrome anyway (Other browsers don't have the same limits).



Alternate method, for the fastest action but slower webpage:

Regarding:

(the page is loading and then you can see the div move), which is something I wish to avoid.

There are only two ways to do anything before DOMContentLoaded that work in Chrome:

  1. You can set mycss.css to hide the div until after you've moved it. This might be the most cost-effective method, performance wise.
  2. Or, you can override document.createElement(). This will respond to the new element as fast as possible (assuming it's created before DOMContentLoaded), but it might slow down the page overall, by a noticeable amount.

Set the content script to run at document_start, and the override code must be injected. So, the script would look like:

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);
}


Do not try to use jQuery for this.

这篇关于Javascript并不总是在Chrome扩展中运行,我应该在什么时候运行它?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆