【问题标题】:Using waitForKeyElements, is it possible to prevent the key element from being displayed, and only display it after it's modified by my code?使用waitForKeyElements,是否可以防止显示关键元素,仅在我的代码修改后才显示?
【发布时间】:2015-08-26 18:18:16
【问题描述】:

我有 this userscript (在 Stack Overflow 的大力帮助下编写) 用于网站 metal-archives.com

它的结构是这样的:

function appendColumn(...) {
    // code for appending column
    // code for making the table sortable   
}

waitForKeyElements ("table", appendColumn);        

脚本运行良好,除了在您切换子标签(表格)时出现视觉故障/延迟

切换时,额外的(第 6 列)最初会按预期显示。但随后,表格会暂时以其原始形式显示,然后最终以应有的形式显示第 6 列。

要查看此内容,请安装脚本,访问 this typical target page,然后切换子选项卡(Complete Discography、Main、Lives、Demos、Misc 等)。
它看起来像这样:


我试图通过添加使初始表格不出现:

GM_addStyle(".display.discog {display: none;} ");

appendColumn() 的开头和:

GM_addStyle(".display.discog {display: inline !important;} "); 

appendColumn()结尾。
但这没有任何区别。


我在该页面上使用了 Firefox 网络监视器,似乎当您切换标签时:

  • 代码立即修改表(从缓存中加载??--因为网络监视器中没有条目)。
  • 然后从服务器加载表格(相关的 HTML 文件)。
  • 然后表最后一次修改。

如何更改代码(在使用waitForKeyElements 时)以防止显示关键元素,仅在我的代码修改后才显示?

或者如何加快响应速度?

谢谢。

【问题讨论】:

    标签: javascript jquery css ajax greasemonkey


    【解决方案1】:

    我加载了您的脚本,添加了时间线,并对其进行了测试。从 AJAX 完成到表格被修复并完成所用的时间只有 400 到 500 毫秒!对于大多数人和情况来说,这已经足够快了。

    但是,对于那些你绝对想挤出毫秒的时间,你可以切换到MutationObservers。这些是挑剔、脆弱且跨浏览器可移植性较差,但速度很快。
    在这种情况下,MutationObservers 将 AJAX 到固定表的时间缩短到 20 到 40 毫秒的范围内。

    我建议使用像 Mutation Summary 这样的库来减轻过程中的一些痛苦。

    简单 waitForKeyElements() 实现转换为 Mutation Summary:

    1. 添加

      @require https://raw.githubusercontent.com/rafaelw/mutation-summary/master/src/mutation-summary.js
      

      到您的元数据块。

    2. 将您的 waitForKeyElements 回调和 simple 选择器插入此结构:

      var muteObserver = new MutationSummary ( {
          callback: handleDiscographyChanges,
          rootNode: $( {ANY-JQUERY-SELECTOR} )[0],
          queries: [ {element: {A-SIMPLE-SELECTOR}} ]
      } );
      
      function handleDiscographyChanges (muteSummaries) {
          var mSummary    = muteSummaries[0];
          if (mSummary.added.length) {
              {YOUR-CALLBACK} ( $(mSummary.added[0]) );
          }
      }
      

    例如在这种情况下,更改:

    waitForKeyElements (".display.discog", appendColumn);
    

    收件人:

    var muteObserver = new MutationSummary ( {
        callback: handleDiscographyChanges,
        rootNode: $("#band_disco")[0],
        queries: [ {element: ".discog"} ]
    } );
    
    function handleDiscographyChanges (muteSummaries) {
        var mSummary    = muteSummaries[0];
        if (mSummary.added.length) {
            appendColumn ( $(mSummary.added[0]) );
        }
    }
    

    rootNode 的位置是通过检查页面结构来确定的。




    作为参考,具有 3 种可选方法和计时记录的完整脚本如下。它仅在 Firefox 上进行了测试,但应该也可以与 Tampermonkey 一起使用(也许)。

    查看每行正上方的//OPTION n 行可选择注释掉。

    // ==UserScript==
    // @name        Metal Archives (discography pages) - Reviews column split and sortable tables
    // @include     http://www.metal-archives.com/bands/*
    // @include     http://www.metal-archives.com/band/*
    // @grant       none
    // @require     http://code.jquery.com/ui/1.9.1/jquery-ui.min.js
    // @require     https://greasyfork.org/scripts/2199-waitforkeyelements/code/waitForKeyElements.js?version=6349
    // @require     https://greasyfork.org/scripts/5844-tablesorter/code/TableSorter.js?version=21758
    // @require     https://raw.githubusercontent.com/rafaelw/mutation-summary/master/src/mutation-summary.js
    // ==/UserScript==
    
    function appendColumn(jNode) {
        logTime ("Table fixed");
    
        // STEP 1+2: SPLIT THE 'REVIEWS' COLUMN INTO A 'REVIEWS' COLUMN AND A 'RATINGS' COLUMN
        var tbl = jNode[0];     // table reference
    
        // If the current sub-table has no data, then stop the execution of the function
        if (tbl.rows[1].cells[0].innerHTML == '<em>Nothing entered yet. Please add the releases, if applicable. </em>') {
            return;
        }
    
        var newCell, newText;
    
        const cols = tbl.rows[0].cells.length - 1;
    
        var tr = tbl.tHead.children[0],
        th = document.createElement('th');
    
        th.innerHTML = "Ratings";
        th.className = "ratingsCol";
        tr.appendChild(th);
    
        for (i = 1; i < tbl.rows.length; i++) {
            k = tbl.rows[i].cells[cols].innerHTML;    // Retrieve the content of the current cell of the Review column and store it to variable k
    
    
            re1 = /<a [^>]*>[^(]*[(]([^)]+)/ ;        // (RegEx which matches the 'Ratings' percentage(incl.the % symbol)
            l = re1.exec(k);                          // (Execute the RegEx and store it to variable l)
    
            newCell = tbl.rows[i].insertCell(-1);     // Add a new cell (for the new 'Ratings' column ) -for each row-
    
            if (re1.test(k) != 0){                    // If the RegEx has matches, (only) then create new cells with...
    
                re0 = /(<a [^>]*>)[0-9]*[^(]/ ;       // (RegEx which matches the reviews URL)
                url = re0.exec(k);                    // (Execute the RegEx and store it to variable url)
    
                newCell.innerHTML = url[1] + l[1] + '</url>'; // ...the Ratings percentage (which is also a link to the Reviews)...
    
    
                re2 = /<a [^>]*>([0-9]*)[^(]/ ;       // (RegEx which matches the 'Reviews' number)
                m = re2.exec(k);                      // (Execute the RegEx and store it to variable m)
    
                newCell = tbl.rows[i].cells[cols];    //
                newCell.innerHTML = url[1] + m[1] + '</url>'; // ...and the Reviews number (which is also a link to the Reviews)
            }
        }
    
        //  STEP 3: MAKE THE DISCOGRAPHY TABLE SORTABLE  (using the jQuery plugin "tablesorter")
        $(tbl).tablesorter ( {
            cssAsc: 'up',
            cssDesc: 'down',
            headers: {
                  0: {sorter: false}
            }
        } );
    }
    
    //OPTION 1
    //waitForKeyElements (".display.discog", appendColumn);
    
    $(document).ajaxComplete (function (e, xhr, config){
        logTime ("Ajax complete");
        //OPTION 2
        return; //-- For compare test
    
        if (config.url.indexOf ('/tab/') != -1){
            $(".display.discog").each ( function () {
                appendColumn ( $(this) );
            } );
        }
    } );
    
    $("#band_disco > ul > li").on ("click", "a.ui-tabs-anchor", function (zEvent) {
        logTime (zEvent.target.textContent + " tab was clicked.");
    } );
    
    function logTime (lableTxt) {
        var tNow    = new Date ();
        console.log (tNow.toLocaleFormat ('%H:%M:%S') + "." + tNow.getMilliseconds (), " <== " + lableTxt);
    }
    
    //OPTION 3
    //*--- Remove leading slash, from this line, to comment out block, below.
    var muteObserver = new MutationSummary ( {
        callback: handleDiscographyChanges,
        rootNode: $("#band_disco")[0],
        queries: [ {element: ".discog"} ]
    } );
    //*/ -- Tail end of optional comment block
    
    function handleDiscographyChanges (muteSummaries) {
        var mSummary    = muteSummaries[0];
        if (mSummary.added.length) {
            appendColumn ( $(mSummary.added[0]) );
        }
    }
    

    请注意,此示例中省略了样式代码和一些原始 cmets。

    【讨论】:

    • 虽然我在您发布它的那天接受并赞成这个答案,但我只是想对这个伟大的、如此详细的答案表示感谢!这远远超出了我的预期!谢谢!我很感激
    【解决方案2】:

    waitForKeyElements 是一种插入内容的慢速方法。这是您看到您所看到的渲染行为的原因之一。

    第一次切换选项卡时正确呈现的原因是因为它被隐藏并且在隐藏时正确调整。当标签显示时,更新内容以反映尚未调整的服务器的最新消息。 waitForKeyElements 然后注意到更改并再次触发以进行更正。

    使用 ajaxComplete,您可以在首次加载内容时隐藏面板。

    数据首次返回时隐藏面板:

    $(document).ajaxComplete(function(e, xhr, config){
       if(config.url.indexOf('/tab/') != -1){                     // Because the tables URLs are like `www.metal-archives.com/band/discography/id/xxx/tab/lives`
           $('.ui-tabs-panel').css('visibility', 'hidden');
       }
    });
    

    appendColumn 函数中显示面板:

    function appendColumn(...) {
        // code for appending column
        // code for making the table sortable   
        $('.ui-tabs-panel').css('visibility', 'visible');
    }
    

    编码愉快!

    【讨论】:

    • 我不介意更改 waitForKeyElements。但它很实用,因为它正在传递关键元素(jNode)的节点 - 即回调函数(appendColumn)的相关表。通过ajaxComplete 无法通过点头。
    • 我用更好的方法更新了代码。在这种情况下,是一种混合方法。
    • 感谢您的帮助,但即使使用您的新方法,我仍然需要等效于 waitForKeyElements 的jNode,即一种将关键元素的节点传递给appendColumn 的方法。 (我编辑了你的答案,将正确的 url 添加到第一个代码部分)
    • 我更新的答案不会改变您对 waitForKeyElements 的使用,因此应该让您像往常一样访问节点。
    • 您可以通过在我的答案中使用OPTION 2 之类的代码来使这个答案几乎有效。但是,当 AJAX 完成时,它并没有多大帮助,新表仍然不存在。插入表时会有额外的延迟。 ...此外,如果更改 @grant 模式,此答案的方法很脆弱并且可能会中断。
    猜你喜欢
    • 2020-10-30
    • 1970-01-01
    • 2023-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-19
    相关资源
    最近更新 更多