代码如下,复制到全局作用域即可用
代码语言:javascript复制const ConsoleGuard = {
// 该方法用于跳转空白页面
openCallback() {
try {
window.open('about:blank', '_self');
}
catch (e) {
const btn = document.createElement('button');
btn.addEventListener('click', () => {
window.open('about:blank', '_self');
});
btn.click();
}
},
// 该方法适用于Safari浏览器,由于尝试在Safari中debugger无效,所以需要单独写
observeSafari() {
const div = document.createElement('div');
// 定义DOM节点对象属性的修饰符,当节点id被读取时,跳转空白页
Object.defineProperty(div, 'id', {
get: () => {
this.openCallback();
},
});
// 在Safari等部分浏览器中,打印一个DOM节点时,如果控制台开启,浏览器会读取上面的属性,否则不会
console.log(div);
},
observe() {
const obj = Object.create(null);
// 记录当前时间
let t = Date.now();
// 修改对象属性的取值方法
Object.defineProperty(obj, 'a', {
get: () => {
// 当对象属性的取值方法被触发时,判断时间间隔是否大于100ms
if (Date.now() - t > 100) {
// 如果打开了控制台,将弹出debugger,时间间隔一定会大于100ms,此时跳转空白页
this.openCallback();
}
},
});
// 定时打印obj.a触发属性的get方法进行判断
setInterval(() => {
// 更新时间t,关键点
t = Date.now();
// debugger,如果控制台开启,则会弹出debugger,否则不会
(function debug() {}).constructor('debugger')(); // debugger
// 触发obj.a的get方法
console.log(obj.a);
}, 200);
},
init() {
const userAgent = window.navigator.userAgent.toLowerCase();
if (userAgent.includes('safari') && !userAgent.includes('chrome')) {
this.observeSafari();
}
else {
this.observe();
}
},
};
ConsoleGuard.init();
代码思想很简单,就是打开控制台时,将页面跳转到空白页,关键在于判断控制台是否被打开。 这里写了两个方法,一个是适用于Safari的observeSafari,另一个是适用于Chrome、Firefox等浏览器的observe方法。
在Safari中,打印一个DOM节点时,如果控制台被打开,则会读取节点的属性;如果没有,则不会读取。因此,只需要在节点对象属性的取值修饰符中写入跳转空白页的代码即可。这样,当控制台被打开时,打印DOM节点时将读取节点属性,由于我们在属性的get方法中写入了跳转空白页面的代码,所以在调用属性的取值方法时会进行跳转。
在Chrome、Firefox等浏览器中需要借助debugger来实现该功能,因此如果用户手动关闭了debug,功能将失效。
debugger用于在JS代码中设置断点,只有在控制台打开时debugger才会起作用。因此我们可以借助一个定时器来实现功能。定时器的定时任务中记录一下该段代码执行的起始时间,之后进行debugger,在任务结束时用结束时间减去起始时间获得该任务执行的总时长。如果总时长大于或等于人手关闭debugger的最小时长,比如100ms,则认为执行了debugger。由于debugger只有在控制台打开时才会执行,所以此时可认为打开了控制台。