【问题标题】:Chrome extension: Modifying the content of a webpageChrome 扩展:修改网页内容
【发布时间】:2016-11-08 02:09:01
【问题描述】:

我正在尝试制作一个简单的 Chrome 扩展程序,通过将其替换为短文本来“阻止”网站 Reddit 的内容。这是我目前所拥有的:

ma​​nifest.json

{
"manifest_version": 2,

"name": "BlockIt",
"description": "Block Reddit, increase productivity!",
"version": "1.0",

"browser_action": {
  "default_icon": "icon.png",
  "default_title": "BlockIt"
},

"permissions": [
  "storage", "tabs",
  "http://www.reddit.com/*"
],

"content_scripts": [
  {
    "matches": [ "*://reddit.com/*" ],
    "js": ["content-script.js"]
  }
] 
}

popup.html

<!doctype html>
<html>
  <head>
    <style>
      body {
        font-family: Verdana, Arial, Helvetica, Tahoma, sans-serif;
        background-color:#EFF7FF;
        margin: 5px 5px 5px 5px;
        width: 110px;
        height: 100%;
        text-align:center;
      }
    </style>
    <!--Scripts-->
      <script src="popup.js"></script>
  </head>
  <body>
    <h2>BlockIt!</h2>
    <div id="en"><label for="enable">Enable BlockIt</label> <input id="enable" type="checkbox" style="vertical-align:middle; position:relative; bottom: 1px;"/>
    </div>
  </body>
</html>

popup.js

document.addEventListener('DOMContentLoaded', function () {
    document.querySelector('#enable').addEventListener('change', changeHandler);
});

function changeHandler() {
    if (enable.checked) {
        chrome.storage.sync.set({ 'enable': true }, function () { });
    }
}

content-script.js

var content = document.getElementsByTagName("body");
var text = "BlockIt enabled (to disable, click on the icon).";
//TODO: replace content with text

我现在有两个主要问题:我不知道我应该如何修改网页内容并将其替换为上面的text,我不知道如何注入@ 987654327@ 选中popup.html 中的复选框时。我该如何解决这个问题?

编辑:我对我的代码进行了以下更改:

content-script.js

chrome.storage.sync.get({ enable: false }, items=> {
    if (items.enable) {
        document.body.textContent = "BlockIt enabled (to disable, click on the icon).";
    }
});

它成功改变了网页的正文,但现在的问题是popup.html的内容也变成了相同的文本。似乎是什么问题?

编辑 2: 我在popup.html 中删除了content-scrip.js。复选框的状态仍然不存在。这似乎是一个简单的解决方案,但我似乎无法修复它。任何帮助将不胜感激。

【问题讨论】:

  • 这确实是两个截然不同的问题。首先,我们需要知道您想要替换什么。您要替换整个&lt;body&gt;(例如document.body.textcontent=text;)、整个&lt;document&gt; 等吗?将webRequests 屏蔽到redit.com 可能更容易。
  • @Makyen 我想替换输入 body 。阻止webRequests时是否可以显示自定义消息?
  • 是的,您可以显示阻止webRequest 的自定义消息。但是,您这样做的方式是不同的。您可以将请求重定向到您的扩展程序中包含阻止消息的 HTML 文件。
  • Arg... 我的第一条评论中有错字。应该是document.body.textContent=text;(注意textContent中的大写C)。
  • 仅供参考:从 Stack Overflow 的角度来看,您最近的两个编辑都应该是 new Questions(您可以在新问题中找到指向此问题的链接以获取上下文)。此外,当您对问题进行编辑时,没有人会收到通知。如果你想通知特定的人,你需要在他们写的问题或答案上发表评论,或者添加一个评论,其中包括他们的用户名,前面有一个@(例如@Makyen,对我来说)。您只能通过@/comment 指定一个人,但您评论的问题/答案的原始发布者始终会收到通知。

标签: javascript html google-chrome google-chrome-extension


【解决方案1】:

一种可能性是使用chrome.storage.sync.get() 在将 content-script.j 注入页面时获取启用状态:

content-script.js

chrome.storage.sync.get({enable:false}, items=> {
    if(items.enable) {
        document.body.textContent="BlockIt enabled (to disable, click on the icon).";
    }
});

这对于当前页面是不可逆的。鉴于您的用户可能希望该阻止是可逆的,而无需重新加载页面,您可能需要考虑一种不同的方法来完成您的阻止,而不是替换所有内容。

此外,这只会替换启用阻止后加载的页面的&lt;body&gt;。它不会影响已经加载的页面。您可能希望使用chrome.tabs.query() 来获取当前显示reddit.com 的选项卡列表。然后,您需要使用 chrome.tabs.executeScript() 再次注入脚本。

类似:

//This requires the "tabs" permission.
//Execute after you have stored the data to chrome.storage.sync (e.g. in the callback)
chrome.tabs.query({url:"*://reddit.com/*"},tabs=>{
    tabs.forEach(tab=>{
        chrome.tabs.executeScript(tab.id,{file:"content-script.js"});
    });
});

【讨论】:

  • 感谢您的帮助。只是确定一下,=&gt; 应该是函数名称的一部分吗?
  • 不,items=&gt;{} 是写function(items) {} 的更短的方式。他们被称为Arrow functions。它们是 ES6 中引入的 JavaScript 中的新事物。您不应该将它们用于一般的 JavaScript 编程,因为并非所有浏览器都支持该语法。但是,对于 Chrome 扩展,我们知道它将在确实支持语法的 Chrome 上运行。我用它是因为它写起来更快。如果您愿意,我可以将答案更改为使用function(...){...}
  • 没关系,您不必更改答案,因为您已向我解释了答案。再次感谢:)
  • 我很高兴能够提供帮助。如果您在将其实际放入代码中有任何问题,请随时要求澄清。
  • @coriandres,我不确定您为什么使用该答案中的任何方法。根据您在问题中描述的内容以及您显示的代码,无需使用任何这些方法。鉴于您在问题中有 manifest.json,您已经将内容脚本注入到页面中。该答案中的方法仅在您需要直接与网页上已经运行的脚本进行交互时才使用,您不需要这样做。您可能需要通过更改document&lt;head&gt; 来禁用此类脚本,但不要使用这些方法。
【解决方案2】:

使用webRequest API 请求重定向来阻止可能更节省资源。

假设您有一个页面blocked.html 代替内容显示。

然后,再次假设扩展状态存储在 chrome.storage.sync 中,如 Mayken 的回答所示。您将需要该值的同步缓存,因为重定向必须是同步的。

// Background script
var enabled;

function cacheEnabled() {
  chrome.storage.sync.get({enable: false}, data => {
    enabled = data.enable;
  });
}

cacheEnabled();
chrome.storage.onChanged.addListener(cacheEnabled);

chrome.webRequest.onBeforeRequest.addListener(
  details => {
    if (enabled) {
      return { redirectUrl: chrome.runtime.getURL("blocked.html") };
    }
  },
  {
    urls: ["*://*.reddit.com/*"],
    types: ["main_frame", "sub_frame"]
  },
  ["blocking"]
);

这需要权限"webRequest", "webRequestBlocking", "*://*.reddit.com/*"

注意:这不是最佳解决方案:最好根据enabled 注册/取消注册监听器,而不是在监听器内部检查它(应该尽可能快)。这留作练习。

【讨论】:

    猜你喜欢
    • 2016-07-11
    • 1970-01-01
    • 2020-06-13
    • 2013-03-09
    • 2012-02-08
    • 1970-01-01
    • 2016-03-31
    • 2011-08-31
    • 1970-01-01
    相关资源
    最近更新 更多