【问题标题】:How can I detect that new content has been loaded in response to a scroll trigger?如何检测是否已加载新内容以响应滚动触发器?
【发布时间】:2014-07-24 04:22:00
【问题描述】:

我正在 Facebook 上运行一个脚本,要求我在“朋友”窗口中获取人员的 ID(这可能不是完成此特定任务的最有效方式,但因为我想知道如何一般来说,这是一个很好的例子)。

这意味着如果我的朋友数量过多,我必须向下滚动 Facebook 才能将他们添加到页面。

我添加了将页面向下滚动到页脚的逻辑,但我不知道如何强制获取 ID 的函数在内容加载后运行。

目前,我已经使用 setTimeout 几秒钟 - 显然,这不能保证在适当的时间,所以我想知道如何正确地做到这一点:

var k;
function doit(){

    k = document.getElementsByClassName("_698");

    var g= Array.prototype.slice.call(k);
    confirm(g.length);
    // the confirm is just to make sure it's working 
    // (if i don't use setTimeout it'll return a smaller number 
    //  since not all the friends were included)

} 

window.addEventListener("load", function(){ 
  document.getElementById( "pageFooter" )
    .scrollIntoView();setTimeout(doit,3000);
  });

【问题讨论】:

    标签: javascript facebook greasemonkey tampermonkey


    【解决方案1】:

    Crayon Violent 详细介绍了如何在his answer to JavaScript detect an AJAX event 中完成此操作。诀窍是挂钩底层 XMLHttpRequest 对象,以便检测何时发送请求。

    我已经重写了一些逻辑,使其更适合您的需求:

    //
    // Hooks XMLHttpRequest to log all AJAX requests. 
    // Override ajaxHook.requestCompleted() to do something specific 
    // in response to a given request.
    //
    var ajaxHook = (function()
    {
       // we're using a self-executing function here to avoid polluting the global
       // namespace. The hook object is returned to expose just the properties 
       // needed by client code.
       var hook = { 
         // by default, just logs all requests to the console. 
         // Can be overridden to do something more interesting.
         requestCompleted: function(xmlHttp, url, method) { console.log(url); } 
       };
    
       // hook open() to store URL and method
       var oldOpen = XMLHttpRequest.prototype.open;
       XMLHttpRequest.prototype.open = function(method, url)
       {
          this.hook_method = method;
          this.hook_url = url;
          oldOpen.apply(this, arguments);
       }
    
       // hook send() to allow hooking onreadystatechange
       var oldSend = XMLHttpRequest.prototype.send;
       XMLHttpRequest.prototype.send = function()
       {
          var xmlhttp = this;
    
          //hook onreadystatechange event to allow processing results
          var oldReadyStateChange = xmlhttp.onreadystatechange;
          xmlhttp.onreadystatechange = function()
          {
             oldReadyStateChange.apply(xmlhttp, arguments);
    
             if ( this.readyState === 4 ) // completed
             {
                hook.requestCompleted(xmlhttp, 
                  xmlhttp.hook_url, xmlhttp.hook_method);
             }
          };
    
          oldSend.apply(this, arguments);
       };
    
       return hook;
    })();
    

    在您的用户脚本中加载这段代码后,您可以按如下方式实现您的逻辑:

    var k;
    function doit()
    {
        k = document.getElementsByClassName("_698");
    
        var g= Array.prototype.slice.call(k);
        confirm(g.length);
    } 
    
    window.addEventListener("load", function()
    {     
       ajaxHook.requestCompleted = function(xmlhttp, url, method)
       {
          // is this the request we're interested in? 
          // (Facebook appears to load friends from a URL that contains this string)
          if ( /AllFriendsAppCollectionPagelet/.test(url) ) 
          {
             // Facebook defers rendering the results here, 
             // so we just queue up scraping them until afterwards
             setTimeout(doit, 0); 
          }
       };
    
      // trigger loading of more friends by scrolling the bottom into view
      document.getElementById( "pageFooter" )
        .scrollIntoView();
    });
    

    【讨论】:

    • 不熟悉 ajax 但似乎是个不错的起点,您是否将 ajaxHook 定义为使用自身的函数?
    • 我很难理解其中的一些,你介意我们聊聊吗?
    • 这个问题应该可以帮助您理解该结构,@user336:stackoverflow.com/questions/592396/… - 如果您对此处的代码有更广泛的问题,您可能只想问一个新问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-04
    • 1970-01-01
    • 1970-01-01
    • 2021-08-08
    • 2013-04-16
    • 1970-01-01
    • 2011-05-31
    相关资源
    最近更新 更多