前端開發中如何在JS文件中檢測用戶瀏覽器是否打開了調試面板(F12打開開發者工具)?


有個奇淫巧技,具體原理未知,測試chrome可以

(function () {
var re = /x/;
var i = 0;
console.log(re);

re.toString = function () {
return "第 " + (++i) + " 次打開控制台";
};
})();


謝謝邀請。

因為安全性原因,javascript是不可以檢測到的。

這裡會有一些投機取巧的方法,不過各有各的局限性。

-------------------------------

[1] 適用於大多瀏覽器,受限於彈出式控制台頁面。

這裡要用javascript去判斷 window.innerHeight 和 window.outerHeight, 以及window.innerWidth 和 window.outerWidth 的差別,如果它們中任意一組有極大的差值,我們就可以猜測這個頁面其實是打開了控制台的。甚至可以檢測到頁面初始化的情況下控制台就是打開著的情況。

代碼如下:

(function(){
//當瀏覽器內寬和外寬的差大於20,或者內高和外高的差大於100的情況下
if(
window.outerWidth - window.innerWidth &> 20 ||
window.outerHeight - window.innerHeight &> 100){
// 在這裡放入你的代碼
}
})();

不過如果控制台是以新頁面的方式打開的話,這個方法久沒轍了。。。

-------------------------------

[2]適用Chrome瀏覽器,受限於非Chrome瀏覽器

這裡我們新創建一個Object, ES6 允許我們自定義獲取Object時候返回什麼,這裡用到了Object.defineProperty的方法,具體請看這裡:Object.defineProperty()。而當Chrome控制台在列印Object的時候,它會獲取到這個Object的id, 所以我們要自定義當獲取id時候觸發的事件。

代碼如下:

var x = document.createElement("div");
Object.defineProperty(x, "id", {
get:function(){
// 在這裡放入你的代碼
alert("Console is opened");
}
});
console.log(x);
// 如果控制台打開
// output: Console is opened

-------------------------------

其實還有另一個方法,是讓控制台連續列印一串數字,控制台打開時候和關閉時候所用的時間是不同的,所以通過時間差來判斷控制台是否打開。個人覺得這個方法不可取,故沒有在此列出。

希望可以幫到你~


請參考 javascript - Find out whether Chrome console is open

翻譯並總結如下:

1.根據瀏覽器窗口大小變化

var widthThreshold = window.outerWidth - window.innerWidth &> threshold;
var heightThreshold = window.outerHeight - window.innerHeight &> threshold;
var orientation = widthThreshold ? "vertical" : "horizontal";

2.從輸出時間來判斷

function isConsoleOpen() {
var startTime = new Date();
debugger;
var endTime = new Date();

return endTime - startTime &> 100;
}

如果控制台打開,debugger這裡會使其執行中斷

3.使用瀏覽器輸出對象時獲取實時引用的方式

前面已經有答案提到了,就不寫了,不過舉個例子來說明chrome獲取對象實時的例子吧。(控制台會保留console的內容)

我們在利用控制台查看對象,點擊後展開的對象屬性是實時的。假如對象在輸出後又有改動,最好使用JSON.stringify去輸出 。4.通過設置對象的屬性的getter方法

原理:當控制台在輸出的某個對象時,是會去get對象屬性的,因此會調用到屬性的getter。

var checkStatus;

var element = new Image();
// var element = document.createElement("any");
element.__defineGetter__("id", function() {
checkStatus = "on";
});

setInterval(function() {
checkStatus = "off";
console.log(element);
console.clear();
document.querySelector("#devtool-status").innerHTML = checkStatus;
}, 1000)


想到一個偏方,應該適用於所有瀏覽器。

var check = (function () {
var callbacks = [], timeLimit = 50, open = false;
setInterval(loop, 2000);
return {
addListener: function (fn) {
callbacks.push(fn);
},
cancleListenr: function (fn) {
callbacks = callbacks.filter(function (v) {
return v !== fn;
});
}
}
function loop() {
var startTime = new Date();
debugger;

if (new Date() - startTime &> timeLimit) {
if (!open) {
callbacks.forEach(function (fn) {
fn.call(null);
});
}
open = true;
} else {
open = false;
}
}
})();

check.addListener(function () {
alert("Open Devtool");
});


謝邀。

問題不是很清晰,如果是判斷用戶是否在打開網頁後打開控制台,就去嗅探可見區域寬高的改變。如果是判斷用戶是否一開始打開瀏覽器,就去通過window.screen.height、window.screen.availHeight和頁面可見高度的關係來判斷,不過這個不準確。


Github上有個很小的類庫devtools-detect,專門用來檢測開發者工具有沒有被打開,支持Chrome, Firefox,Safari ,Firebug。


var el = new Image();
Object.defineProperty(el, "id", {
get: function() {
alert("ACTIVED");
}
});
console.log("%c", el);


方法如下,當你每次按下f12都會if(window.consolewindow.console.log){

console.log("打開了控制台")

}


讓高級框架來告訴你,帶有生命周期的前端框架。

例如 react,vue都支持生命周期。

寫個原生獲取屏幕寬高的函數。

寫個比對函數,a時執行前抓到的參數。b,是每個鉤子函數抓取到的值。

比對值不一樣,就發出提示。

在頁面載入之前執行一次

在載入完成時在執行一次

數據改動時在執行一次,

頁面銷毀時執行一次。

每個鉤子時執行一次。應該就能知道了吧!!!


訪問一下 samy kamkar - home 這個網站,然後打開控制台,就知道是如何監控控制台是否打開了。作者samy kamkar用了自定義事件 devtoolschange

以下代碼我從VM代碼里摳出來的,自己可以複製到代碼里執行一下

if (!window.$)
(s = (z = document).getElementsByTagName(x = "script")[0]).parentNode.insertBefore(z.createElement(x), s).src = "//ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js";
var ua = navigator.userAgent.toLowerCase();
var msie = ua.indexOf("msie") &> -1;
if (!msie navigator.appName == "Netscape" ua.indexOf("trident/") &> -1)
msie = true;
var safari = ua.indexOf("chrome") &> -1;
var chrome = ua.indexOf("safari") &> -1;
var firefox = ua.indexOf("firefox") &> -1;
function dc(event) {
if (event.button == 2)
return false
}
document.onmousedown = dc;
(function() {
if (typeof window.CustomEvent === "function")
return false;
function CustomEvent(event, params) {
params = params || {
bubbles: false,
cancelable: false,
detail: undefined
};
var evt = document.createEvent("CustomEvent");
evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
return evt
}
CustomEvent.prototype = window.Event.prototype;
window.CustomEvent = CustomEvent
})();
(function() {
"use strict";
var devtools = {
open: false,
first: true,
orientation: null
};
window.lq = devtools;
var threshold = 160;
var emitEvent = function(state, orientation, eventname) {
if (!eventname)
eventname = "devtoolschange";
window.dispatchEvent(new CustomEvent(eventname,{
detail: {
open: state,
orientation: orientation
}
}))
};
setInterval(function() {
var widthThreshold = window.outerWidth - window.innerWidth &> threshold;
var heightThreshold = window.outerHeight - window.innerHeight &> threshold;
var orientation = widthThreshold ? "vertical" : "horizontal";
if (!(heightThreshold widthThreshold) (window.Firebug window.Firebug.chrome window.Firebug.chrome.isInitialized || widthThreshold || heightThreshold)) {
if (!devtools.open || devtools.orientation !== orientation) {
emitEvent(true, orientation);
if (lq.first) {
lq.first = false;
emitEvent(true, orientation, "firstevent")
}
}
devtools.open = true;
devtools.orientation = orientation
} else {
if (devtools.open) {
emitEvent(false, null);
if (lq.first) {
lq.first = false;
emitEvent(false, null, "firstevent")
}
}
devtools.open = false;
devtools.orientation = null
}
}, 1e3);
if (typeof module !== "undefined" module.exports) {
module.exports = devtools
} else {
window.devtools = devtools
}
})();
var deb = 0;
var intr, _b;
var timerMax = deb ? 2e3 : 500;
var element = new Image;
var egg8msg = "No source for you! You found easter egg #8. Close the console to return to samy.pl ;)";
var utm = "__utmq";
var firstload = 1;
var solecon = clone(console);
function clone(obj) {
if (null == obj || "object" != typeof obj)
return obj;
var copy = obj.constructor();
for (var attr in obj)
if (obj.hasOwnProperty(attr))
copy[attr == "log" ? "go" : attr] = obj[attr];
return copy
}
function al(x) {
if (!deb)
return;
solecon.go(x)
}
function rmbody() {
al("rm1");
if (readCookie(utm) == 2)
return;
al("rm2");
createCookie(utm, 2, 365 * 10);
location.reload(true)
}
function noconsole3() {
al("NOC3");
noconsole()
}
function noconsole2() {
al("NOC2");
noconsole()
}
function noconsole() {
al("noc1");
if (readCookie(utm) == 1)
return;
al("noc2");
createCookie(utm, 1, 365 * 10);
location.reload(true)
}
function egg8log() {
if (msie)
solecon.go(egg8msg);
else
solecon.go("%c" + egg8msg, "background: black; color: #00ff00; font-size: x-large;")
}
if (window.location.href.indexOf("noint") == -1) {
if (readCookie(utm) != 1) {
al("ngood");
var noconyet = 0;
var threshold = 160;
var widthThreshold = window.outerWidth - window.innerWidth &> threshold;
var heightThreshold = window.outerHeight - window.innerHeight &> threshold;
var orientation = widthThreshold ? "vertical" : "horizontal";
if (!(heightThreshold widthThreshold) (window.Firebug window.Firebug.chrome window.Firebug.chrome.isInitialized || widthThreshold || heightThreshold)) {
if (!devtools.open || devtools.orientation !== orientation) {}
} else {
al("n1");
noconyet = 1
}
}
element.__defineGetter__("id", function() {
al("dg");
if (intr)
clearTimeout(intr);
if (!_b)
rmbody();
intr = setTimeout(noconsole2, timerMax * 1.5)
});
if (chrome || safari) {
intr = setTimeout(noconsole3, timerMax * 2);
al("c||s");
setInterval(function() {
solecon.go(element);
solecon.clear();
egg8log()
}, timerMax)
} else {
al("elsec||s");
window.addEventListener("devtoolschange", function(e) {
if (e.detail.open) {
rmbody();
egg8log()
} else {
noconsole()
}
})
}
}
function createCookie(name, value, days) {
if (days &> 0)
eraseCookie(name);
if (days) {
var date = new Date;
date.setTime(date.getTime() + days * 24 * 60 * 60 * 1e3);
var expires = "; expires=" + date.toGMTString()
} else var expires = "";
document.cookie = name + "=" + value + expires + "; path=/"
}
function readCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(";");
for (var i = 0; i &< ca.length; i++) { var c = ca[i]; while (c.charAt(0) == " ") c = c.substring(1, c.length); if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length) } return null } function eraseCookie(name) { createCookie(name, "", -1) }


chrome打開微博,再打開console,再刷新,跳轉到http://m.weibo.cn。原理未知。


把console的屬性都打出來看看有啥不一樣的地方


var checkStatus;

var element = new Image();

element.__defineGetter__("id", function() {
checkStatus = "on";
});

setInterval(function() {
checkStatus = "off";
console.log(element);
console.clear();
alert(checkStatus);
}, 5000)


監測console這個函數?


可以試試keydowm事件監聽,判斷code是不是f12那個鍵


去監聽用戶是否按下了F12就行啦。

Talk is cheap,show my code.

--------------------------------------

window.onkeydown = function(event) {

event = event || window.event;

event.keyCode === 123 alert("你按下了F12");

}


推薦閱讀:

如何評價谷歌開發的 Chrome 流量節省程序?
除了改hosts,還有什麼方法可以進入chrome應用店?(改hosts之後,應用無法添加)
在不更新 chrome 的前提下如何訪問 chrome 網上應用商店,安裝插件?

TAG:前端開發 | JavaScript | Chrome擴展程序 |