简体   繁体   English

如何使GreaseMonkey脚本在显示之前影响页面中的元素?

[英]How to make a GreaseMonkey script affect elements in a page before they're displayed?

I'm trying to ensure that images in a certain website are not displayed, but the alt text is still displayed. 我正在尝试确保不显示某个网站中的图像,但仍会显示替代文字。 Initially I attempted to accomplish this with Stylish (using Firefox) and asked the following question: 最初我尝试使用Stylish(使用Firefox)完成此操作并询问以下问题:

How to force an image's alt text to display instead of the image? 如何强制显示图像的alt文本而不是图像?

The accepted answer provided me with an alternative solution using Greasemonkey. 接受的答案为我提供了使用Greasemonkey的替代解决方案。 The script uses waitForKeyElements to hide images even if they're added using AJAX. 该脚本使用waitForKeyElements隐藏图像,即使它们是使用AJAX添加的。

I changed the given script to the following: 我将给定的脚本更改为以下内容:

// ==UserScript==
// @name     _Hide pics except for alt text
// @include  http://YOUR_SERVER.COM/YOUR_PATH/*
// @require  http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js
// @require  https://gist.github.com/raw/2625891/waitForKeyElements.js
// @grant    GM_addStyle
// ==/UserScript==

GM_addStyle ( "                                 \
    * {                                         \
        background-image: none !important;      \
    }                                           \
" );

waitForKeyElements ("img", hideImageExceptForAltText);

function hideImageExceptForAltText (jNode) {
    var imgAlt = jNode.attr("alt");
    var imgTitle = jNode.attr("title");

    jNode.css("display", "none");

    var newSpan = $("<span></span>");
    newSpan.attr("title", imgTitle);
    newSpan.append(imgAlt);

    jNode.parent().append(newSpan);
}

Just like the original script, this has the problem that the images are still displayed for a few moments as the page is loading. 就像原始脚本一样,这有一个问题,即在页面加载时图像仍会显示片刻。

Is it possible to ensure that the given function will prevent images on a page from being displayed immediately, so that they won't be visible at all? 是否可以确保给定的功能可以防止页面上的图像立即显示,以便它们根本不可见?

EDIT: Brock Adams' reply had the clue I was missing. 编辑:布洛克亚当斯的回复有我不知道的线索。 In case anyone is looking for something like this, the following is what I ended up using. 如果有人正在寻找这样的东西,以下是我最终使用的东西。 It works fine on the site I needed it for, but I can't guarantee it will work on other sites or other browsers than Firefox. 它在我需要它的网站上运行良好,但我不能保证它可以在除Firefox之外的其他网站或其他浏览器上运行。

The following hides images and replaces them with a link (except for background images). 以下内容隐藏图像并用链接替换它们(背景图像除外)。 Clicking that link will display the image. 单击该链接将显示图像。

// ==UserScript==
// @name        TCRF images
// @namespace   SOMETHING
// @include     http://YOUR_SERVER.COM/YOUR_PATH/*
// @require     http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js
// @require     https://gist.github.com/raw/2625891/waitForKeyElements.js
// @version     1
// @grant       GM_addStyle
// @run-at      document-start
// ==/UserScript==

GM_addStyle ( "\
    * {\
       background-image: none !important;\
    }\
\
    img.gmImgHideHidden {\
       display: none !important;\
    }\
" );

var num = 0;

function gmImgHideShowImg(imgId, linkId)
{
    // Using plain JavaScript because the page itself may not have jquery
    var img = document.getElementById(imgId);
    img.className = img.className.replace( /(?:^|\s)gmImgHideHidden(?!\S)/g , '' );

    var lnk = document.getElementById(linkId);
    lnk.parentNode.removeChild(lnk);
}

// Exporting the "show image" function so that it can be used in the webpage
unsafeWindow.gmImgHideShowImg = exportFunction(gmImgHideShowImg, unsafeWindow);

waitForKeyElements ("img", hideImageExceptForAltText);

function hideImageExceptForAltText (jNode) {
    var imgId = jNode.attr("id");

    // Ensuring an id exists so the image can be searched for later
    if(typeof(imgId) == "undefined")
    {
        imgId = "gmImgHideImg" + num;
        jNode.attr("id", imgId);
    }

    var imgDisp = jNode.css("display");

    var imgAlt = jNode.attr("alt");
    jNode.addClass("gmImgHideHidden");

    var linkId = "gmImgHideLink" + num;

    var linkNode = $("<a></a>");
    linkNode.attr("id", linkId);
    linkNode.append("Image: " + imgAlt);
    linkNode.attr("onclick", "gmImgHideShowImg('" + imgId + "', '" + linkId + "'); return false;");

    jNode.parent().append(linkNode);

    num++;
}

MutationObserver is without a doubt the best solution here. MutationObserver毫无疑问是这里最好的解决方案。 Combined with early injection by @run-at document-start we can make the script pretty much bullet-proof. 结合@run-at document-start早期注入,我们可以使脚本非常防弹。 Check out this fiddle (tested with Firefox 40) to see it in action. 看看这个小提琴 (用Firefox 40测试)看看它的实际效果。

I think the code is pretty self-explanatory. 我认为代码非常明显。 I've annotated the subtleties, but leave a comment if there's anything you don't understand. 我已经注释了这些细微之处,但如果你有什么不明白的话,请留言。

// ==UserScript==
// @run-at document-start
// ==/UserScript==
"use strict";

/* part one: <img> elements */

(new MutationObserver(function(Records, Obs) {
    for (let R of Records) {/* examine each mutation record: */
        /* if the record specifies an attribute mutation… */
        if (
            R.attributeName === "src" &&
            (R.target instanceof Element) && /* this check might be necessary */
            R.target.tagName.toLowerCase() === "img" &&
            R.target.getAttribute("src") !== "" /* avoid infinite loop */
        ) {
            R.target.setAttribute("src", "");
        };

        /* if the record specifies a sub-element mutation… */
        for (let N of R.addedNodes) {
            if (
                (N instanceof Element) && /* this check might be necessary */
                N.tagName.toLowerCase() === "img" &&
                N.getAttribute("src") !== "" /* avoid infinite loop */
            ) {
                N.setAttribute("src", "");
            };
        };
    };
})).observe(document, {
    /* changes wot we listen for */
    childList : true,
    subtree : true,
    attributes : true
});

/* part two: background-image styles */

let check_for_head_elem = function(_, Obs) {
    if (!document.head) {return;};
    Obs.disconnect();

    /* apply our style */
    let Style = document.createElement("style");
    document.head.appendChild(Style);
    Style.sheet.insertRule("* {background-image : none !important;}", 0);
};

let check_for_root_elem = function(_, Obs) {
    if (!document.documentElement) {return;};
    Obs.disconnect();

    /* observe until the <head> element is added */
    Obs = new MutationObserver(check_for_head_elem)
    Obs.observe(document.documentElement, {childList : true});
    check_for_head_elem(null, Obs); /* check here because it might exist already */
};

{/* observe until the <html> element is added */
    let Obs = new MutationObserver(check_for_root_elem);
    Obs.observe(document, {childList : true});
    check_for_root_elem(null, Obs); /* check here because it might exist already */
};

There are some other ways to get images on the page that I haven't taken into consideration ( <iframe> , <svg> , <canvas> , <li> bullet points), but if necessary you should be able to use mutation observers or CSS to take care of those too. 还有一些其他方法可以在页面上获取我没有考虑过的图像( <iframe><svg><canvas><li>项目符号点),但如有必要,您应该可以使用变异观察器或CSS也照顾这些。

A simple, robust way to do this is to set CSS first-thing, before any of the rest of the page loads. 一个简单,健壮的方法是在页面的任何其他页面加载之前设置CSS first-thing。

@run-at document-start and GM_addStyle() do this. @run-at document-startGM_addStyle()执行此操作。 (on Firefox; not tested on latest Tampermonkey) (在Firefox上;未在最新的Tampermonkey上测试)

That way, the images are not displayed even for a fraction of a second, like they are with the original code or with a complicated, finicky MutationObserver approach. 这样,图像即使在几分之一秒内也不会显示,就像它们使用原始代码或复杂,挑剔的MutationObserver方法一样。

This complete script shows the process: 这个完整的脚本显示了该过程:

// ==UserScript==
// @name     _Hide pics except for alt text
// @include  http://YOUR_SERVER.COM/YOUR_PATH/*
// @require  http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js
// @require  https://gist.github.com/raw/2625891/waitForKeyElements.js
// @grant    GM_addStyle
// @run-at   document-start
// ==/UserScript==
GM_addStyle ( "                                 \
    * {                                         \
        background-image: none !important;      \
    }                                           \
    img {                                       \
        display: none !important;               \
    }                                           \
" );

/*--- $(document).ready() is not always needed for modern Firefox, but
    use for maximum portability, when script runs at document-start.
*/
$(document).ready ( function () {
    waitForKeyElements ("img", hideImageExceptForAltText);
} );

function hideImageExceptForAltText (jNode) {
    var imgAlt      = jNode.attr("alt")     || "";
    var imgTitle    = jNode.attr("title")   || "";

    jNode.after ('<span title="' + imgTitle + '">' + imgAlt + '</span>');
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在显示页面内容之前运行greasemonkey脚本? - how to run greasemonkey script before the page content is displayed? 使用jQuery的Greasemonkey,如何编写隔油纸脚本来修改页面DOM元素? - Greasemonkey with jQuery, how to write the greasemonkey script to modify page DOM elements? 在greasemonkey脚本中显示元素后(而不是页面完全加载后)立即修改元素? - Modify elements immediately after they are displayed (not after page completely loads) in greasemonkey script? 如何制作一个油脂猴子脚本,当按下某个键时,该脚本单击页面上的一个按钮? - How to make a greasemonkey script that clicks a button on page when a key is pressed? Greasemonkey脚本使固定定位元素静态 - Greasemonkey script to make Fixed Positioned Elements Static 我的Greasemonkey脚本找不到页面上的元素(链接)吗? - My Greasemonkey script is not finding the elements (links) on the page? 在显示页面之前运行脚本 - running a script before the page is displayed 如何获取GreaseMonkey脚本以侦听将特定类插入页面的元素 - How to get a GreaseMonkey script to listen for elements with a specific class being inserted into a page 刷新页面的Greasemonkey脚本 - Greasemonkey script that refreshes page Greasemonkey 如何在页面中的 *anything* 之前运行? - How does one have Greasemonkey run before *anything* else in the page?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM