2011-11-26 14 views

回答

56

在AJAX請求上重新運行腳本代碼的智能方法是關注頁面的關鍵位並檢查更改。

例如,假設一個網頁包含的HTML像這樣:

<div id="userBlather"> 
    <div class="comment"> Comment 1... </div> 
    <div class="comment"> Comment 2... </div> 
    ... 
</div> 

和你想的腳本做一些事情,每個評論,因爲它排在

現在你攔截所有AJAX。請撥打電話 或聽 DOMSubtreeModified (不建議使用),或使用MutationObserver s,但這些方法可能會變得棘手,挑剔和過於複雜。

在wild頁面上獲取ajax-ified內容的一種更簡單,更可靠的方法是使用下面的waitForKeyElements函數進行輪詢。

例如,該腳本將突出包含 「啤酒」 的意見,因爲他們AJAX式:

// ==UserScript== 
// @name   _Refire on key Ajax changes 
// @include   http://YOUR_SITE.com/YOUR_PATH/* 
// @require   http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js 
// ==/UserScript== 

function highlightGoodComments (jNode) { 

    //***** YOUR CODE HERE ***** 

    if (/beer/i.test (jNode.text())) { 
     jNode.css ("background", "yellow"); 
    } 
    //... 
} 
waitForKeyElements ("#userBlather div.comment", highlightGoodComments); 

/*--- waitForKeyElements(): A utility function, for Greasemonkey scripts, 
    that detects and handles AJAXed content. 

    IMPORTANT: This function requires your script to have loaded jQuery. 
*/ 
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) { 
     btargetsFound = true; 
     /*--- 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. 
       var cancelFound  = actionFunction (jThis); 
       if (cancelFound) 
        btargetsFound = false; 
       else 
        jThis.data ('alreadyFound', 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 
             ); 
       }, 
       300 
      ); 
      controlObj [controlKey] = timeControl; 
     } 
    } 
    waitForKeyElements.controlObj = controlObj; 
} 

更新:

爲方便起見,waitForKeyElements()現在hosted on GitHub

This answer shows an example of how to use the hosted function

+0

我道歉,錯誤實際上在於zeroclipboard,而不是你的功能。我在調試時發現一個有趣的事情是,如果'bWaitOnce'設置爲'true',代碼實際上會觸發兩次,不確定這是否是有意或無意的 – RozzA

+0

@RozzA,我希望看到能夠證明這一點的代碼。部分代碼可能會觸發兩次(或多次) - 按設計。但是'actionFunction'應該只給每個給定節點觸發一次。 –

+0

@BrockAdams,爲什麼'setInterval'而不是'MutationObserver'? –

0

另一種方式 - 更簡單,更小但更不靈活 - 使用JavaScript時間延遲等待AJAX​​/jQuery加載和完成。例如,如果下面的HTML首次加載後動態生成:

<div id="userBlather"> 
    <div class="comment"> Comment 1... </div> 
    <div class="comment"> Comment 2... </div> 
    ... 
</div> 

然後像這樣的的Greasemonkey腳本,將能夠修改:

// Wait 2 seconds for the jQuery/AJAX to finish and then modify the HTML DOM 
window.setTimeout(updateHTML, 2000); 

function updateHTML() 
{ 
    var comments = document.getElementsByClassName("comment"); 
    for (i = 0; i < comments.length; i++) 
    { 
     comments[i].innerHTML = "Modified comment " + i; 
    } 
} 

見蒞臨指導:Sleep/Pause/Wait in Javascript