【问题标题】:How to prevent the browser from loading a web app in vanilla JavaScript?如何防止浏览器在 vanilla JavaScript 中加载 Web 应用程序?
【发布时间】:2018-08-18 21:12:33
【问题描述】:

我编写了以下 Greasemonkey 脚本来防止自己访问一些网络应用程序(网站),通常这些我觉得有点上瘾。这是我阻止我的浏览器显示这些网站的最接近的方法:

// ==UserScript==
// @name        blocko
// @include     *
// ==/UserScript==

window.addEventListener('load', function() {
    let sites = ['example-1.com', 'example-2.com', 'example-3.com'];
    let dotTLD_andAllAfterIt = /\..+/;
    let href = window.location.href;
    for (let i = 0; i < sites.length; i++) {
        if (href.includes(sites[i])) {
            let domain = sites[i].replace(dotTLD_andAllAfterIt, '');
            document.body.innerHTML =`
                <div style="direction: ltr; position: fixed; top: 0; z-index: 999999; display: block; width: 100%; height: 100%; background: red">
                  <p style="position: relative; top: 40%; display: block; font-size: 66px; font-weight: bold; color: #fff; margin: 0 auto; text-align: center">
                    Enough with this ${domain} bullshit!
                  </p>
                </div>
          `;
        }
    }
}, true);

我对我在这里的成就不满意,因为这个脚本让我进入网站,在极少数情况下我需要等待 1/2/3/4 甚至 5 秒或更长时间,直到该站点将消失,而我打印到屏幕上的带有红色背景的消息将改为出现。因此,我不情愿地接触到我想避免的网站内容。

我希望阻止浏览器甚至通过 JavaScript 导航到网站。有一个名为“BlockSite”的 Chrome 插件可以帮助解决这个问题,我试图检查它的(巨大的)源代码,但无法理解它如何阻止用户被移动到网站,这与我的脚本不同上面将用户移动到网站,但在几秒钟后(在触发load 事件之后),网站消失并显示一条消息。

请分享一种完全阻止自己进入网站的方法,例如“BlockSite”。

【问题讨论】:

  • 您是要制作浏览器插件/扩展还是要在网站内部实现脚本?
  • 您好!我不打算创建浏览器扩展。该功能应在特定域的范围内工作。
  • 编辑hosts 文件以包含127.0.0.1 example-1.com 之类的内容。一个简单的 Google 搜索(“编辑主机文件以防止访问网站”)可能会有所帮助。

标签: javascript browser google-chrome-extension greasemonkey tampermonkey


【解决方案1】:

作为一种解决方案,您可以覆盖网站中所有链接的 onclick 方法。 然后决定是否让用户点击链接。

const blackList = [`example-1.com`, `example-2.com`]

function onClick(event) {
  const href = this.href.match(/^(?:https?:)?(?:\/\/)?(?:[^@\n]+@)?(?:www\.)?([^:\/\n]+)/i)
  if (!href) return
  const domain = href[1]
  if (blackList.includes(domain)) {
    event.stopPropagation()
    event.preventDefault()
    document.body.innerHTML =`
      <p>
        Enough with this ${domain} bullshit!
      </p>
    `;
  }
}

const elements = document.getElementsByTagName(`a`);
for(let element of elements) {
  element.onclick = onClick
}

.:更新:.

好的,让我解释一下上面的代码。

代码将click 侦听器添加到当前页面的所有链接 (&lt;a href="..."&gt;...&lt;/a&gt;)。当用户点击上面的功能时会被触发。

const href = this.href.match - 我们从 href 唯一的域部分中提取,以便比较 url 是否存在于我们的黑名单中 -> if (blackList.includes(domain))

this - 指链接属性href 更多信息请查看article

这是demo,这是source code

【讨论】:

  • 我们必须使用正则表达式吗?
  • 请考虑在您认为合适的地方添加一些 cmets。
  • @user9303970 好的,我已经用一些解释更新了我的答案
  • 苏丹,你测试过代码吗,我试着测试过,对我来说它不起作用......另外,你同意在第二次更新中就正则表达式说几句话,也许通过上下文呈现不同的“上下文”或匹配字符组。
【解决方案2】:

只要您使用window load 事件,您就需要等待。您需要改用DOMContentLoaded 事件。区别解释here on this answer

如果你改变它会工作得更快

window.addEventListener('load', function() {
   //Your Code
}, true);

document.addEventListener("DOMContentLoaded", function(event) {
   //Your Code
});

有许多免费扩展程序可用于阻止不需要的域。如果您想为 chrome 构建一个,请告诉我,在这种情况下,我可以进一步提供帮助。

更新:根据 cmets 删除以下段落

但是,如果您想进行自己的扩展,那么您需要特定于浏览器。因为你需要为不同的浏览器编写不同的扩展。

【讨论】:

  • 您的最后一段不再是真的,因为大多数主流浏览器(包括 Chrome、Firefox 和 Edge,但不幸的是不包括 Safari)或多或少都支持相同的跨浏览器 WebExtension API .方便的是,WebExtension content scripts 也与 Greasemonkey / Tampermonkey 用户脚本非常相似,因此将用户脚本转换为独立扩展相当简单(基本上,只需添加一个 manifest.json 文件)。
  • @IlmariKaronen 我不知道,段落已删除。
【解决方案3】:

阻止网站在浏览器中显示的最佳方法是在加载之前使用 CSS。像这样的东西应该可以很好地完成这项工作:

/* hide all child elements of <body> */
body > * {
  display: none !important;
}
/* just in case, hide text directly inside <body> too */
body {
  color: transparent !important;
  font-size: 0px !important;
}
/* inject an overlay to show a message and to cover up anything that might
   still somehow be visible after the styles above */
body::before {
  content: 'Enough with this BS!';
  display: block;
  width: 100%;
  height: 100%;
  position: fixed;
  z-index: 999999;
  text-align: center;
  font-size: 36pt;
  font-family: sans-serif;
  color: red;
  background: black;
}

使用Stylus 之类的用户样式扩展,您只需将上面的 CSS 设置为您想要阻止的所有域的用户样式。该扩展将在页面加载之前将用户样式注入页面,从而完全防止页面上的任何内容甚至短暂可见。

或者,您也可以通过将样式包装在用户脚本中并自己将其注入页面来实现类似的结果。您可以使用 @run-at document-start 标头指令使用户脚本尽可能早地运行,甚至在页面加载之前,再次将任何实际页面内容显示的风险降至最低:

// ==UserScript==
// @name        Enough with this BS
// @version     0.1
// @description Block any sites this script runs on with a rude message.
// @author      Ilmari Karonen
// @match       *://*.example.com/*
// @grant       none
// @run-at      document-start
// ==/UserScript==

var style = `
    /* hide all child elements of <body> */
    body > * {
      display: none !important;
    }
    /* just in case, hide text directly inside <body> too */
    body {
      color: transparent !important;
      font-size: 0px !important;
    }
    /* inject an overlay to show a message and to cover up anything that might
       still somehow be visible after the styles above */
    body::before {
      content: 'Enough with this ${location.hostname} BS!';
      display: block;
      width: 100%;
      height: 100%;
      position: fixed;
      z-index: 999999;
      text-align: center;
      font-size: 36pt;
      font-family: sans-serif;
      color: red;
      background: black;
    }`;

// Inject style into page
var styleElem = document.createElement( 'style' );
styleElem.type = 'text/css';
styleElem.textContent = style;
( document.head || document.documentElement ).appendChild( styleElem );

这种方法的一个优点是您可以使用 JS 自定义每个站点的样式,例如在上面的消息中包含网站的名称。

请注意,上面的脚本不包含任何用于匹配您要阻止的网站的正则表达式;相反,它在用户脚本标题中使用@match expressions 来告诉用户脚本管理器仅在某些站点上运行它。 (上面的示例标头只是阻止 example.com 及其任何子域上的所有内容。)

这样做的一个优点是它比正则表达式匹配更有效,因为脚本根本不会在任何其他页面上运行;另一个是大多数用户脚本管理器提供了一个 UI 来添加额外的匹配和/或排除模式,而无需直接编辑脚本。

(另外可能值得注意的是,我使用ES2015 template literal 将样式表嵌入到 JS 代码中,因为旧式 JS 字符串不能跨越多行。SO 上突出显示的代码似乎不正确理解那个语法,这就是为什么它看起来有点可笑。)

【讨论】:

    【解决方案4】:
    • 如果想停止,试试这个:window.stop documentation(无法停止加载包含它的文档)
    • 试试这个如果 你想阻止页面重新加载/重定向链接:onbeforeunload documentation(不要阻止自动加载,但允许用户选择是否跟随链接)

      window.onbeforeunload = function(e) {
      
        var dialogText = 'Are you sure?';
      
         e.returnValue = dialogText;
      
         return dialogText;
      
      };
      

    【讨论】:

    • 这似乎是最好的方法,你能分享一个代码来阻止对给定集合中所有网站的访问吗?
    • 我重新评论,只是因为我真的不确定你是否看到我的评论。
    • 我赞成您的回答,因为这似乎是一种最有前途的方法。
    • thnx,我只是没有足够的时间来演示答案)我编辑了我的答案,可能我的答案对你不是很有用
    猜你喜欢
    • 2011-01-04
    • 2016-03-31
    • 1970-01-01
    • 2014-03-18
    • 1970-01-01
    • 2021-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多