Chrome 监听 console 打开
这个算是 Chrome only 其他的我没测试,也不想测试。因为我的控制台脚本仅仅在 Chrome 下加载。
如果你需要全平台,那么这肯定不是你需要的结果。
需求
其实我很早就想折腾这个了,但是,,因为懒,拖了很久,直到周末,我看到服务器上统计,发现流量翻了一倍,结果访问量还是一样的时候,我才下决心折腾。
知之为知之不知谷歌之
一开始,谷歌一番,发现有两种思路。
第一个是 sindresorhus 大神写的 devtools-detect,算是全平台兼容(除IE),但独立窗口打开的时候是检测不到的。
另一个是咱们国人 zswang 写的 jdetects,目测也是 Chrome only,当然我的灵感也来至于他。
虽然有两个现成的,但这都不是我满意的模式,于是乎就有了本次 Chrome 控制台环境探索之旅。
分析控制台环境
根据 zswang 的 jdetects 得知,控制台会解析节点元素的 id 属性。
那么为什么会解析呢?或者他还做了什么处理呢?
打开浏览器,按 F12 打开 console 后输入 debugger 按回车,然后按两次 F11,OK 完成。
如果你的 Chrome 50 的话,映入眼帘的是密密麻麻的一大串压缩的字符,好在他们没 uglify,否则我就默默关了,也不会有这篇文章了。
点左下角 {} 格式化代码后,变的非常漂亮,但是没有注释了,我记得之前版本都是有注释的,更容易阅读。
大致预览下代码,最终定位到 660 行的 _describe 方法处,其他都不管我也不知道干嘛的,分析需要的代码即可。
// 用易懂的形式,描述各种对象方法,如正则,日期,node,数组,函数 等。
_describe: function(obj) {
if (this.isPrimitiveValue(obj)) // 如果是原始值不描述
return null;
// 获取类型名包括 ArrayLike,但不是 Object.prototype.toString,有兴趣可以单独查看源码
var subtype = this._subtype(obj);
if (subtype === "regexp") // 正则和日期输出 toString 后的结果。
return toString(obj);
if (subtype === "date")
return toString(obj);
if (subtype === "node") { // dom 节点处理,这里是重点
// 获取节点名,text comment 等只有 nodeName
var description = obj.nodeName.toLowerCase();
switch (obj.nodeType) { // 节点类型
case 1: // Element 类型
description += obj.id ? "#" + obj.id : ""; // 获取元素 id
var className = obj.className; // 获取元素 class
description += (className && typeof className === "string") ? "." + className.trim().replace(/\s+/g, ".") : "";
break;
case 10: // DocumentType 类型
description = "<!DOCTYPE " + description + ">";
break;
}
return description;
}
// 获取内部构造函数名,可能类似 Object.prototype.toString
var className = InjectedScriptHost.internalConstructorName(obj);
// 类似数组的就输出 对象名[长度] 比如 Array[3], jQuery.fn.jQuery.init[2] 之类的
if (subtype === "array") {
if (typeof obj.length === "number")
className += "[" + obj.length + "]";
return className;
}
if (typeof obj === "function") // 函数 toString
return toString(obj);
if (isSymbol(obj)) { // Symbol 处理
try {
return (InjectedScriptHost.callFunction(Symbol.prototype.toString, obj)) || "Symbol";
} catch (e) {
return "Symbol";
}
}
// 错误类型处理
if (InjectedScriptHost.subtype(obj) === "error") {
try {
var stack = obj.stack;
var message = obj.message && obj.message.length ? ": " + obj.message : "";
var firstCallFrame = /^\s+at\s/m.exec(stack);
var stackMessageEnd = firstCallFrame ? firstCallFrame.index : -1;
if (stackMessageEnd !== -1) {
var stackTrace = stack.substr(stackMessageEnd);
return className + message + "\n" + stackTrace;
}
return className + message;
} catch (e) {}
}
return className;
}
OK,代码挺简单的,看完基本就知道为什么 jdetects 可以检测控制台是否被打开了。
那么现在我们知道,其实完全可以借助 正则,日期,函数 的 toString 实现,而且更简单,例如:
var re = /x/;
var i = 0;
console.log(re);
re.toString = function () {
return '第 ' + (++i) + ' 次打开控制台';
};
简单又好用,也不需要定时器或 resize 事件监视,性能更是好到不用说。需要注意的是这里的 re.toString 必须在 console.log 之后定义,否则没打开控制台 toString 也会执行。
如果只是监听控制台打开,这个几行代码足以,但是我还没想到监听控制台关闭方法。
这么简单的代码,我就不写成插件装逼了,需要的时候直接用即可。在 runjs 上写了个 demo,打开预览下效果吧!
预览: http://sandbox.runjs.cn/show/vjtgjbzg
后序
控制台环境下有很多功能都很方便很好用,多读读会发现很多神奇的技巧。
本文同步至我的个人博客:http://www.52cik.com/2016/04/27/chrome-console-open.html
Chrome 监听 console 打开的更多相关文章
- javascript 反调试 监听用户打开了Chrome devtool
let div = document.createElement('div'); let loop = setInterval(() => { console.log(div); ...
- [Android Pro] 监听WIFI 打开广播
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-perm ...
- android监听屏幕打开关闭广播无响应的情况
android在屏幕打开和关闭的时候会发出广播,但是如果receiver配置在AndroidManifest.xml中时,receiver是接受不到任何广播的. <receiver androi ...
- 如何实现监听 console.log
var lastLog; console.oldLog = console.log; console.log = function(str) { console.oldLog(str); lastLo ...
- chrome 监听touch类事件报错:无法被动侦听事件preventDefault
先上错误信息: Unable to preventDefault inside passive event listener due to target being treated as passiv ...
- [Android Pro] 监听Blutooth打开广播
<uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission a ...
- Android onclick监听事件打开新界面
一.新建工程 二.新建XML代码 新建一个Button <Button android:layout_width="wrap_content" android:layout_ ...
- oracle 监听服务OracleOraDb11g_home1TNSListener打开后立马停止错误
首先我真得吐槽一下,我安装这个破软件感觉真的是把能遇到的错误都遇到一遍了,生气!!!!!!! 关于监听服务OracleOraDb11g_home1TNSListener打开后立马停止这个错误,我的解决 ...
- 连接linux数据库Oracle时报错ORA-12541: TNS: 无监听程序
远程服务器的数据库服务未开启,以及监听未打开 连接oracle 启动服务,startup 切换到oracle /bin 目录,cd $ORACLE_HOME/bin 启动监听, lsnrctl sta ...
随机推荐
- Sql Server之旅——第八站 复合索引和include索引到底有多大区别?
周末终于搬进出租房了,装了宽带....才发现没网的日子...那是一个怎样的与世隔绝呀...再也受不了那样的日子了....好了,既然网 安上去了,还得继续我的这个系列. 索引和锁,这两个主题对我们开发工 ...
- 0001 Oracle数据库安装
从这个月初开始学习Oracle,因为完全是零起步,就从Oracle的下载安装开始一点一点学起,今天把系统重新做了,就再安装了一遍Oracle11gR2,把安装过程记录一下: 一.安装Oracle数据库 ...
- 学习myBatis - 如何配置myBatis
这篇文章主要学习如何配置myBatis. 要学习新东西要讲究方法,要从三个层面去理解它:它是什么(what),为什么要学它(why),怎么用它(how).有了学习方法学习的效率才高. 1.myBati ...
- Java api 入门教程 之 JAVA的String 类
1.String对象的初始化 由于String对象特别常用,所以在对String对象进行初始化时,Java提供了一种简化的特殊语法,格式如下: String s = “abc”; s = “Java语 ...
- 烂泥:ubuntu下配置msmtp+mutt发送邮件
本文由ilanniweb提供友情赞助,首发于烂泥行天下 想要获得更多的文章,可以关注我的微信ilanniweb. 本文主要介绍如何在Linux下使用msmtp+mutt发送邮件,当然Linux下发送邮 ...
- 高性能MySQL笔记 第6章 查询性能优化
6.1 为什么查询速度会慢 查询的生命周期大致可按照顺序来看:从客户端,到服务器,然后在服务器上进行解析,生成执行计划,执行,并返回结果给客户端.其中“执行”可以认为是整个生命周期中最重要的阶段. ...
- x01.Lab.OpenCV: 计算机视觉
横看成岭侧成峰,计算视觉大不同.观看的角度不同,成像自然不同,这对计算机视觉来说,是个大麻烦.但计算机视觉应用如此广泛,却又有不得不研究的理由.指纹机大家都用过吧,这不过是冰山之一角.产品检测,机器人 ...
- shell脚本实现随机筛选
#!/bin/bash name=(val1 val2 val3 val4 ...) a=$() #以时间产生随机数向39取余得到0~38的值
- android ListView 和 BaseAdapter 应用
步聚: 1.建立ListView对象:--(作用:绑定Adapter呈现数据) 2.建立ListView实现的Item栏位.xml布局:--(作用:实现ListView的栏位布局) 3.建立Item. ...
- python enumerate函数用法
enumerate函数用于遍历序列中的元素以及它们的下标 i = 0 seq = ['one', 'two', 'three'] for element in seq: print i, seq[i] ...