停止执行 Javascript 函数(客户端)或调整它
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3972038/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Stop execution of Javascript function (client side) or tweak it
提问by Yousuf
I want to stop the execution of one single line from a site, so that the whole page is read by the browser except that single line. Or the browser may simply skip the execution of that javascript function.
我想停止从站点执行一行,以便浏览器读取整个页面,除了那一行。或者浏览器可能会简单地跳过该 javascript 函数的执行。
OR
或者
Is there way i can tweak the javascript somehow so that the random number generating function in javascript do not generate random number, but the numbers i want...
有没有办法我可以以某种方式调整javascript,以便javascript中的随机数生成函数不生成随机数,但我想要的数字...
I dont have access to the site on which the script is hosted so all this needs to be done client side.
我无权访问托管脚本的站点,因此所有这些都需要在客户端完成。
回答by Brock Adams
Firefox currently supports the beforescriptexecuteevent(as of Version 4, released on March 22, 2011)?.
火狐目前支持的beforescriptexecute事件(截至4版,发布于2011年3月22日)?.
With that event and the // @run-at document-start
directive, Firefox and Greasemonkey now seem to do a good job intercepting specific <script>
tags.
与该事件和该// @run-at document-start
指令,Firefox和Greasemonkey的现在似乎做好拦截特定的<script>
标签。
This is still not possible for Chrome+Tampermonkey. For anything but Firefox+Greasemonkey, you will need to use techniques as shown in the other answers, below, of write a full browser extension.
这对于 Chrome+Tampermonkey 仍然是不可能的。对于 Firefox+Greasemonkey 以外的任何东西,您都需要使用下面其他答案中所示的技术来编写完整的浏览器扩展。
The checkForBadJavascripts
functionencapsulates this. For example, suppose the page had a <script>
tag like so:
该checkForBadJavascripts
函数封装了这一点。例如,假设页面有一个<script>
像这样的标签:
<script>
alert ("Sorry, Sucka! You've got no money left.");
</script>
You could use checkForBadJavascripts
like so:
你可以checkForBadJavascripts
像这样使用:
checkForBadJavascripts ( [
[ false,
/Sorry, Sucka/,
function () {
addJS_Node ('alert ("Hooray, you\'re a millionaire.");');
}
]
] );
to get a much nicer message. (^_^)
See the inline documentation, in checkForBadJavascripts, for more.
得到更好的消息。(^_^)
有关更多信息,请参阅checkForBadJavascripts 中的内联文档。
To see a demonstration in a complete script, first visit this page at jsBin. You will see 3 lines of text, two of them added by JS.
要查看完整脚本中的演示,请首先访问jsBin 上的此页面。您将看到 3 行文本,其中两行是 JS 添加的。
Now, install this script(View source; it's also below.) and revisit the page. You will see that the GM-script deleted one bad tag and replaced another with our "good" JS.
现在,安装此脚本(查看源代码;它也在下面。)并重新访问该页面。你会看到 GM 脚本删除了一个坏标签,并用我们的“好”JS 替换了另一个。
?Note that only Firefox supports the beforescriptexecute
event. And it was removed from the HTML5 spec with no equivalent capability specified.
? 请注意,只有 Firefox 支持该beforescriptexecute
事件。它从 HTML5 规范中删除,没有指定等效功能。
Complete GM script example(The same as the one at GitHub and jsBin):
完整的 GM 脚本示例(与 GitHub 和 jsBin 中的相同):
Given this HTML:
鉴于此 HTML:
<body onload="init()">
<script type="text/javascript" src="http://jsbin.com/evilExternalJS/js"></script>
<script type="text/javascript" language="javascript">
function init () {
var newParagraph = document.createElement ('p');
newParagraph.textContent = "I was added by the old, evil init() function!";
document.body.appendChild (newParagraph);
}
</script>
<p>I'm some initial text.</p>
</body>
Use this Greasemonkey script:
使用这个 Greasemonkey 脚本:
// ==UserScript==
// @name _Replace evil Javascript
// @include http://jsbin.com/ogudon*
// @run-at document-start
// ==/UserScript==
/****** New "init" function that we will use
instead of the old, bad "init" function.
*/
function init () {
var newParagraph = document.createElement ('p');
newParagraph.textContent = "I was added by the new, good init() function!";
document.body.appendChild (newParagraph);
}
/*--- Check for bad scripts to intercept and specify any actions to take.
*/
checkForBadJavascripts ( [
[false, /old, evil init()/, function () {addJS_Node (init);} ],
[true, /evilExternalJS/i, null ]
] );
function checkForBadJavascripts (controlArray) {
/*--- Note that this is a self-initializing function. The controlArray
parameter is only active for the FIRST call. After that, it is an
event listener.
The control array row is defines like so:
[bSearchSrcAttr, identifyingRegex, callbackFunction]
Where:
bSearchSrcAttr True to search the SRC attribute of a script tag
false to search the TEXT content of a script tag.
identifyingRegex A valid regular expression that should be unique
to that particular script tag.
callbackFunction An optional function to execute when the script is
found. Use null if not needed.
*/
if ( ! controlArray.length) return null;
checkForBadJavascripts = function (zEvent) {
for (var J = controlArray.length - 1; J >= 0; --J) {
var bSearchSrcAttr = controlArray[J][0];
var identifyingRegex = controlArray[J][1];
if (bSearchSrcAttr) {
if (identifyingRegex.test (zEvent.target.src) ) {
stopBadJavascript (J);
return false;
}
}
else {
if (identifyingRegex.test (zEvent.target.textContent) ) {
stopBadJavascript (J);
return false;
}
}
}
function stopBadJavascript (controlIndex) {
zEvent.stopPropagation ();
zEvent.preventDefault ();
var callbackFunction = controlArray[J][2];
if (typeof callbackFunction == "function")
callbackFunction ();
//--- Remove the node just to clear clutter from Firebug inspection.
zEvent.target.parentNode.removeChild (zEvent.target);
//--- Script is intercepted, remove it from the list.
controlArray.splice (J, 1);
if ( ! controlArray.length) {
//--- All done, remove the listener.
window.removeEventListener (
'beforescriptexecute', checkForBadJavascripts, true
);
}
}
}
/*--- Use the "beforescriptexecute" event to monitor scipts as they are loaded.
See https://developer.mozilla.org/en/DOM/element.onbeforescriptexecute
Note that it does not work on acripts that are dynamically created.
*/
window.addEventListener ('beforescriptexecute', checkForBadJavascripts, true);
return checkForBadJavascripts;
}
function addJS_Node (text, s_URL, funcToRun) {
var D = document;
var scriptNode = D.createElement ('script');
scriptNode.type = "text/javascript";
if (text) scriptNode.textContent = text;
if (s_URL) scriptNode.src = s_URL;
if (funcToRun) scriptNode.textContent = '(' + funcToRun.toString() + ')()';
var targ = D.getElementsByTagName ('head')[0] || D.body || D.documentElement;
//--- Don't error check here. if DOM not available, should throw error.
targ.appendChild (scriptNode);
}
回答by Brock Adams
The answer depends on details which were not provided (The exact page and line of code would be best), but here's how you do it in general:
答案取决于未提供的详细信息(最好是确切的页面和代码行),但一般情况下您可以这样做:
If the offending JS code does not fire right away(Fires after
DOMContentLoaded
), then you can use Greasemonkey to replace the offending code. ? EG:var scriptNode = document.createElement ("script"); scriptNode.textContent = "Your JS code here"; document.head.appendChild (scriptNode);
Done.
If the JS code fires immediately, then it gets more complicated.
First, grab a copy of the script and make the desired change to it. Save this locally.Is the offending script in a file or is it in the main page HTML (
<script src="Some File>
versus<script>Mess O' Code</script>
)?If the script is in a file, install Adblock Plusand use it to block loading of that script. Then use Greasemonkey to add your modified code to the page. EG:
var scriptNode = document.createElement ("script"); scriptNode.setAttribute ("src", "Point to your modified JS file here."); document.head.appendChild (scriptNode);
If the script is in the main HTML page, then install either NoScript(best) or YesScriptand use it to block JavaScript from that site.
This means that you will then need to use Greasemonkey to replace all scripts, from that site, that you do want to run.
如果有问题的JS 代码没有立即触发(在 之后触发
DOMContentLoaded
),那么您可以使用 Greasemonkey 替换有问题的代码。? 例如:var scriptNode = document.createElement ("script"); scriptNode.textContent = "Your JS code here"; document.head.appendChild (scriptNode);
完毕。
如果JS 代码立即触发,那么它会变得更加复杂。
首先,获取脚本的副本并对其进行所需的更改。将其保存在本地。有问题的脚本是在文件中还是在主页 HTML(
<script src="Some File>
vs<script>Mess O' Code</script>
)中?如果脚本在文件中,请安装Adblock Plus并使用它来阻止加载该脚本。然后使用 Greasemonkey 将修改后的代码添加到页面。例如:
var scriptNode = document.createElement ("script"); scriptNode.setAttribute ("src", "Point to your modified JS file here."); document.head.appendChild (scriptNode);
如果脚本位于主 HTML 页面中,则安装NoScript(最佳)或YesScript并使用它来阻止来自该站点的 JavaScript。
这意味着您随后需要使用 Greasemonkey 替换该站点中您想要运行的所有脚本。
回答by CertainPerformance
Method 1: using MutationObserver
方法一:使用 MutationObserver
beforescriptexecute
no longer works in Firefox, nor did it work in Chrome. Luckily, there's an alternative, using MutationObserver
, which is quite widely supported. The general idea is to add a MutationObserver at the beginning of pageload, which will run a callback whenever a new node is added to the DOM. Inside the callback, check for the existence of the <script>
tag you want to alter or remove. If it exists, you can tamper with it (such as change its textContent
, or have its src
point somewhere else). Only afterthe callback finishes will the newly added script tag run, so this is an effective way to intercept and change Javascript on a page. Here's a live snippet example:
beforescriptexecute
不再适用于 Firefox,也不适用于 Chrome。幸运的是,还有一种替代方法 using MutationObserver
,它得到了广泛的支持。一般的想法是在页面加载开始时添加一个 MutationObserver,每当有新节点添加到 DOM 时,它都会运行回调。在回调中,检查<script>
您要更改或删除的标签是否存在。如果它存在,您可以篡改它(例如更改它的textContent
,或将其src
指向其他地方)。新添加的script标签只有在回调完成后才会运行,因此这是一种拦截和更改页面Javascript的有效方式。这是一个实时片段示例:
<script>
// This is the userscript code, which runs at the beginning of pageload
// Say we wanted to prevent the loading of the jQuery script tag below:
new MutationObserver((_, observer) => {
const jqueryScriptTag = document.querySelector('script[src*="jquery"]');
if (jqueryScriptTag) {
console.log('Found jQuery script tag; now removing it!');
jqueryScriptTag.remove();
// We've done what we needed to do, no need for the MutationObserver anymore:
observer.disconnect();
}
})
.observe(document.documentElement, { childList: true, subtree: true });
</script>
<div>Example content</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
console.log('After jQuery script tag. If done right, $ should be undefined:');
console.log(typeof $);
</script>
Here's an example userscript that blocks jQuery from loading in the <head>
here on Stack Overflow:
这是一个示例用户脚本,它阻止 jQuery 加载<head>
到 Stack Overflow的此处:
// ==UserScript==
// @name Example jQuery removal
// @include https://stackoverflow.com*
// @run-at document-start
// @grant none
// ==/UserScript==
if (document.head) {
throw new Error('Head already exists - make sure to enable instant script injection');
}
new MutationObserver((_, observer) => {
const jqueryScriptTag = document.querySelector('script[src*="jquery"]');
if (jqueryScriptTag) {
jqueryScriptTag.remove();
observer.disconnect();
}
})
.observe(document.documentElement, { childList: true, subtree: true });
If you install this, you'll see that the loading of jQuery fails, resulting in lots of errors generated by Stack Overflow's JS.
如果你安装这个,你会看到jQuery的加载失败,导致Stack Overflow的JS产生很多错误。
Make sure to attach the MutationObserver as soon as possible - you need @run-at document-start
to attach it before the page loads anything inside the <head>
. (If using Tampermonkey / Chrome, you may need to enable experimental instant script injection to achieve this reliably - go to Tampermonkey Settings, Config mode: Advanced, scroll to the bottom, set Experimental Inject Mode to Instant.)
确保尽快附加 MutationObserver - 您需要@run-at document-start
在页面加载<head>
. (如果使用 Tampermonkey / Chrome,您可能需要启用实验性即时脚本注入以可靠地实现这一点 - 转到 Tampermonkey 设置,配置模式:高级,滚动到底部,将实验性注入模式设置为即时。)
If you're writing userscripts for others, any you're using this technique, make sure to include instructions for instant script injection, since injection is notinstant by default on Chrome.
如果您正在为其他人编写用户脚本,任何您正在使用此技术,请确保包含即时脚本注入的说明,因为默认情况下,Chrome 上的注入不是即时的。
Note that the observer is attached using
请注意,观察者是使用附加的
.observe(document.documentElement, { childList: true, subtree: true });
This attaches the observer to the <html>
element, watches for added and removed immediate children with childList: true
, and watches for added and removed nodes anywhere inside its descendantswith subtree: true
. Such a recursive listener is useful, but it's also computationally expensive on large dynamic pages, so make sure to remove it once it's achieved its purpose.
这武官观测到的<html>
元素,添加和删除的即时儿童手表childList: true
,并添加和删除节点手表及其后代中的任何位置用subtree: true
。这种递归侦听器很有用,但它在大型动态页面上的计算成本也很高,因此请确保在达到目的后将其删除。
On a huge page, calling querySelector
on every mutation could be costly, so you might want to iterate through the mutations
(the first parameter to the observer's callback) and the mutations' addedNodes
instead:
在一个巨大的页面上,调用querySelector
每个突变可能代价高昂,因此您可能希望迭代mutations
(观察者回调的第一个参数)和突变的addedNodes
替代:
<script>
// This is the userscript code, which runs at the beginning of pageload
// Say we wanted to prevent the loading of the jQuery script tag below:
new MutationObserver((mutations, observer) => {
for (const mutation of mutations) {
for (const addedNode of mutation.addedNodes) {
if (addedNode.nodeType === 1 && addedNode.matches('script[src*="jquery"]')) {
console.log('Found jQuery script tag; now removing it!');
addedNode.remove();
// We've done what we needed to do, no need for the MutationObserver anymore:
observer.disconnect();
return;
}
}
}
})
.observe(document.documentElement, { childList: true, subtree: true });
</script>
<div>Example content</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
console.log('After jQuery script tag. If done right, $ should be undefined:');
console.log(typeof $);
</script>
You can also tweak inline scripts by assigning to their textContent
inside the observer callback. The following snippet shows how you can change a random number generator function to always return 10, rather than 1-6:
您还可以通过textContent
在观察者回调内部分配内联脚本来调整内联脚本。以下代码段显示了如何将随机数生成器函数更改为始终返回 10,而不是 1-6:
<script>
// This is the userscript code, which runs at the beginning of pageload
new MutationObserver((mutations, observer) => {
for (const mutation of mutations) {
for (const addedNode of mutation.addedNodes) {
if (addedNode.textContent.includes('const randomNum')) {
addedNode.textContent = addedNode.textContent.replace(
/const randomNum.*/,
'const randomNum = 10;'
);
observer.disconnect();
return;
}
}
}
})
.observe(document.documentElement, { childList: true, subtree: true });
</script>
<button>Roll Die</button>
<div>Results: <span></span></div>
<script>
const [button, span] = ['button', 'span'].map(tag => document.querySelector(tag));
button.onclick = () => {
const randomNum = Math.ceil(Math.random() * 6);
span.textContent = randomNum;
};
</script>
Method 2: using DevTools Local Overrides
方法 2:使用 DevTools 本地覆盖
Method 1 is the technique you can use when writing userscripts for others. But if the userscript is just for yourself, there's an easier method that can work in some situations. See this answer to the question Chrome Dev Tools - Modify javascript and reload: by going to the Sources -> Overrides tab in Chrome Devtools, and enabling local overrides, you can tell the browser to load a local copy of a .js
instead of downloading the site's version. Then you can edit the local copy as desired, and it'll run instead of the built-in script. This is especially useful when tweaking large Javascript files - it's muchmore manageable than the MutationObserver approach.
方法 1 是您在为他人编写用户脚本时可以使用的技术。但是,如果用户脚本仅供您自己使用,则有一种更简单的方法可以在某些情况下使用。请参阅Chrome Dev Tools - Modify javascript and reload问题的答案:通过转到 Chrome Devtools 中的 Sources -> Overrides 选项卡,并启用本地覆盖,您可以告诉浏览器加载 a 的本地副本,.js
而不是下载站点的版本。然后您可以根据需要编辑本地副本,它将运行而不是内置脚本。调整较大的JavaScript文件时,这是非常有用的-这是很多比MutationObserver方法更易于管理。
But, there are some downsides:
但是,有一些缺点:
- To modify inline
<script>// code here</script>
tags, you'll have to download a local copy of the page. (So if the page serves dynamic content through the HTML response, you'll either have to re-save and re-tweak the.html
for your overrides to use the new content, or you'll have to go back to the MutationObserver method.) - This is a technique developersmay be able to understand (after some experimenting), but it's not so user-friendly. It may not be the sort of thing you'd want to walk a casual userscript consumer through.
- 要修改内嵌
<script>// code here</script>
标记,您必须下载页面的本地副本。(因此,如果页面通过 HTML 响应提供动态内容,您要么必须重新保存并重新调整.html
覆盖以使用新内容,要么必须返回到 MutationObserver 方法。) - 这是一种开发人员可能能够理解的技术(经过一些试验),但它不是那么用户友好。它可能不是您想要让临时用户脚本消费者完成的那种事情。
回答by Mic
You can use what is called a bookmarklet.
您可以使用所谓的书签。
Build the js file you want to run on the other site: your.js
构建要在其他站点上运行的 js 文件: your.js
Make an HTML page with the following code:
使用以下代码制作 HTML 页面:
<html>
<body>
<a href="javascript:(function(){var s=document.createElement('SCRIPT');s.src='/url/to/your.js?'+(Math.random());document.getElementsByTagName('head')[0].appendChild(s);})()">
Drag'n Drop this to your bookmarks
</a>
</body>
</html>
Replace /url/to/your.js
with the path of your js file.
替换/url/to/your.js
为您的 js 文件的路径。
Load that small page in your browser and drag'n drop the link to your bookmark bar.
在浏览器中加载那个小页面,然后将链接拖放到书签栏。
Go to the web site you want to hack, and click the bookmark you just created.
This will load your.js
in the page and run the code.
转到您要破解的网站,然后单击您刚刚创建的书签。
这将your.js
在页面中加载并运行代码。
Note: the ?'+(Math.random())
part is to avoid your js being cached, this is not mandatory but it is helpful when you develop your.js
注意:?'+(Math.random())
部分是为了避免您的 js 被缓存,这不是强制性的,但在您开发时很有帮助your.js
回答by Mic
Using TamperMonkey? All you need to add below your // @grant
in the TamperMonkey header is // @require http://urlofyoursite.com/myfile.js
. For example, here is the very top of my TamperMonkey thingie:
使用 TamperMonkey?您需要// @grant
在 TamperMonkey 标头下方添加的所有内容是// @require http://urlofyoursite.com/myfile.js
. 例如,这是我的 TamperMonkey 东西的最顶部:
// ==UserScript==
// @name Project
// @namespace http://tampermonkey.net/
// @version 0.1
// @description try to take over the world!
// @author You
// @match https://docs.google.com/presentation/*
// @grant none
// @require http://cdnjs.cloudflare.com/ajax/libs/annyang/2.1.0/annyang.min.js
// ==/UserScript==