访问动态加载的JS元素

时间:2012-04-14 05:51:20

标签: javascript greasemonkey google-search

我正在尝试编写一个简单的javascript来为Google的搜索工具添加更多选项(按“更多搜索工具”时显示的选项。但是,当我尝试将新元素附加到现有元素时,我收到错误。例如:

var yr = document.getElementById('qdr_y'); 
yr.parent.insertBefore(k,yr);

第二行抛出异常,因为yr为空。通过检查搜索结果页面的直接源代码,我发现基本结果页面仅包含“所有结果”,“更多搜索工具”和隐藏的“更少搜索工具”。所有其他选项都以其他方式注入。

如何访问这些其他元素,以便将新元素添加到正确的位置?

2 个答案:

答案 0 :(得分:1)

你有它:

// ==UserScript==
// @name           TESTE
// @namespace      TESTE
// @description    TESTE
// @include        http*://*.google.*
// ==/UserScript==


var k = document.createElement('div');
k.innerHTML = "<center><b> bla bla </b></center>"
var yr = document.getElementById('gbmm'); 
yr.insertBefore(k,yr.firstChild);

(这只是一个示例。您不应再使用<center><b>标记。

enter image description here

除非你的意思是这样的

enter image description here

然后代码看起来像这样

// ==UserScript==
// @name           TESTE
// @namespace      TESTE
// @description    TESTE
// @include        http*://*.google.*
// ==/UserScript==

var k = document.createElement('li');
k.id = 'myoption'
k.className = 'tbou'
k.innerHTML = "<a href='http://userscripts.org/users/rasg' class='q qs'> Here is my option </a>"
var yr = document.getElementById('clir_1'); 
yr.parentNode.appendChild(k);

另外,请考虑将JQuery添加到GM脚本中。

// @require        http://code.jquery.com/jquery.min.js

编码要容易得多。

*编辑*

根据您的评论

  

我希望将节点插入“所有搜索工具”中   第二个解决方案。但是,你发布的内容正是如此   我已经在做了,除了使用qdr_y而不是clir_1!

以下(非常简单)代码是解决方案

// ==UserScript==
// @name           TESTE 3
// @namespace      TESTE 3
// @description    TESTE 3
// @require        http://code.jquery.com/jquery.min.js
// @include        http*://www.google.com/*
// ==/UserScript==

$(window).load(function(){
    $('.tbpc').click()
    $('.tbt').on('DOMNodeInserted', function() {
        if ($('#my_li').length) { $('#my_li').show() }
        else { $('#whv_').parent().append("<li id='my_li' class='tbou' style=''><a class='q qs' href='http://userscipts.org'>Now i am inside</a>") }
    })
    $('.tbpo').on('click', function() { $('#my_li').hide() })
});

enter image description here

它并不像我想的那样漂亮,但谷歌让我们做坏事:)

答案 1 :(得分:0)

请注意,代码段中的parent应为parentNode

无论如何,通常,对于动态元素,您需要检查并等待目标元素。如果需要点击某些内容,您的脚本必须单击它。 (尝试使用Google网站上的JS功能页面通常效果不佳.Google页面对于脚本来说总是非常“有趣”。;))

您需要自由使用轮询来弥补AJAX延迟。 (挂钩到AJAX事件或使用突变事件都有很高的成功率。轮询效果很好。)

最后,因为它是Google,所以仅仅触发一次民意调查是不够的,因为这些搜索选项会不断被覆盖。

以下是适用于美国版Google搜索结果的示例脚本(需要jQuery):

// ==UserScript==
// @name        _Google Search options add
// @include     http://www.google.com/*
// @require     http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js
// ==/UserScript==

if (window.top != window.self)  //-- Don't run on frames or iframes.
    return;

/*-- This script:
    1) Waits for the "More search tools" control.
    2) Clicks that control.
    3) Waits for the target element
    4) Adds our element before that one.
*/

waitForKeyElements ("#tbpi", clickMoreSearchToolsLink);

function clickMoreSearchToolsLink (jNode) {
    var clickEvent  = document.createEvent ('MouseEvents');
    clickEvent.initEvent ('click', true, true);
    jNode[0].dispatchEvent (clickEvent);

    waitForKeyElements ("#qdr_y", addOurExtraNodes);
}

function addOurExtraNodes (jNode) {
    jNode.before ("<li>Look at me, Ma!</li>");
}


/*--- waitForKeyElements():  A handy, utility function that
    does what it says.
*/
function waitForKeyElements (
    selectorTxt,    /* Required: The jQuery selector string that
                        specifies the desired element(s).
                    */
    actionFunction, /* Required: The code to run when elements are
                        found. It is passed a jNode to the matched
                        element.
                    */
    bWaitOnce,      /* Optional: If false, will continue to scan for
                        new elements even after the first match is
                        found.
                    */
    iframeSelector  /* Optional: If set, identifies the iframe to
                        search.
                    */
) {
    var targetNodes, btargetsFound;

    if (typeof iframeSelector == "undefined")
        targetNodes     = $(selectorTxt);
    else
        targetNodes     = $(iframeSelector).contents ()
                                           .find (selectorTxt);

    if (targetNodes  &&  targetNodes.length > 0) {
        /*--- Found target node(s).  Go through each and act if they
            are new.
        */
        targetNodes.each ( function () {
            var jThis        = $(this);
            var alreadyFound = jThis.data ('alreadyFound')  ||  false;

            if (!alreadyFound) {
                //--- Call the payload function.
                actionFunction (jThis);
                jThis.data ('alreadyFound', true);
            }
        } );
        btargetsFound   = true;
    }
    else {
        btargetsFound   = false;
    }

    //--- Get the timer-control variable for this selector.
    var controlObj      = waitForKeyElements.controlObj  ||  {};
    var controlKey      = selectorTxt.replace (/[^\w]/g, "_");
    var timeControl     = controlObj [controlKey];

    //--- Now set or clear the timer as appropriate.
    if (btargetsFound  &&  bWaitOnce  &&  timeControl) {
        //--- The only condition where we need to clear the timer.
        clearInterval (timeControl);
        delete controlObj [controlKey]
    }
    else {
        //--- Set a timer, if needed.
        if ( ! timeControl) {
            timeControl = setInterval ( function () {
                    waitForKeyElements (    selectorTxt,
                                            actionFunction,
                                            bWaitOnce,
                                            iframeSelector
                                        );
                },
                200
            );
            controlObj [controlKey] = timeControl;
        }
    }
    waitForKeyElements.controlObj   = controlObj;
}