CSS Layout Debugger
https://gist.github.com/addyosmani/fd3999ea7fce242756b1
现在到处都是JavaScript,每天都能知道点新东西。一旦你入了门,你总能从这里或是那里领悟到很多知识。一旦我发现一些有意思的东西,我喜欢去感觉他们的源代码,看一看它是怎么办到的。
今天我想分享Addy Osmani的一行代码 ,这行代码对于你调试你的CSS是很有用的。为了可读性,我把它变成了3行。
[].forEach.call($$("*"),function(a){
a.style.outline="1px solid #"+(~~(Math.random()*(1<<24))).toString(16)
})
*注:Addy Osmani 是Google Chrome开发工程师,他前几天开发的字符串解析模板, 马上被兼容最新ES6标准的io.js采纳。 *
尝试在你浏览器的Console(F12)中运行一下,你会发现页面被不同的颜色块高亮了,这个方法非常简单,但是你自己写的话可能产生非常多的代码,让我们来研究一下它是怎么实现的。
选择一个页面上的所有元素
我们首先需要选择页面上的所有元素。Addy使用了只能在console调试工具中使用的$$
函数,你可以在console中输入$$('a')
自己试一下。它会返回当前页面的所有anchor(链接)元素。
$$
与document.querySelectorAll
是等价的。所以$$('*')
与 document.querySelectorAll('*')
是等价的,有兴趣的话可以看看$ $和$选择器的历史。
对于我来说,$$
的使用已经让我学到了很多。但是选择页面上的所有元素的知识还有很多。Mathias Bynens就在评论中指出document.all
其实也能选取选用元素,而且兼容所有主流浏览器。
遍历所有的元素
现在我们有了一个所有元素的节点列表(NodeList),现在我们想遍历它们,并给他们加上有颜色的边框。我们先看看能从这行代码里发现什么:
[].forEach.call( $$('*'), function( element ) { /* And the modification code here */ });
NodeList看起来像一个Array(数组),你可以使用中括号来访问他们的节点,而且你还可以通过length
属性知道它有多少元素。但是它并没有实现Array的所有接口,因此使用 $$('*').forEach 会返回错误。
在JavaScript的世界里,有一堆看起来像Array但其实不是的对象。如function中的arguments对象。因此在他们身上通过call
和apply
来应用数组的方法是非常有用的。我之前写过一篇文章来解析它们的用法,下面是一个例子:
function say(name) {
console.log( this + ' ' + name );
}
say.call( 'hola', 'Mike' ); // 打印输出 'hola Mike'
// Also you can use it on the arguments object
function example( arg1, arg2, arg3 ) {
return Array.prototype.slice.call(arguments, 1); // Returns [arg2, arg3]
}
之前的一行代码使用[].forEach.call
代替 Array.prototype.forEach.call
减少了代码的编写量 ( 另外一个很有意思的地方 );如果$$('*')
返回是个数组的话,它与$$('*').forEach
是等价的。如果你看看评论,还有人使用for(i=0;A=$$('*');)
让代码变得更短,但是它在全局对象中注入了变量。你可以带上var
声明,如
for(var i=0,B=document.querySelectorAll('*');A=B[i++];){ /* your code here */ }
其中i
和B
将只声明在console的上下文中。
改变元素的颜色
让元素有一个漂亮的边框,这行代码使用了CSS的outline
属性。有一点你可能不知道,在CSS渲染的盒子模型(Box Model)中,outline
并不会改变元素及其布局的位置。因此这比使用border属性要好得多,所以这一部分其实并不难理解
a.style.outline="1px solid #" + color
怎样定义颜色值其实是比较有意思的~~
(Math.random()*(1<<24))).toString(16);
我们想构造的其实是一个16进制的颜色值,像白色FFFFFF
,蓝色0000FF
等等。首先我们学到了可以使用数字类型的toString()
方法进行十进制到16进制的转换。其实你可以用它进行任意进制的转换:
(30).toString(); // "30"
(30).toString(10); // "30"
(30).toString(16); // "1e" 16进制
(30).toString(2); // "11110" 二进制
(30).toString(36); // "u" 36 是最大允许的进制
另一方面,你可以使用parseInt()
方法的第二个参数,将十六进制数转换为十进制:
parseInt("30"); // "30"
parseInt("30", 10); // "30"
parseInt("1e", 16); // "30"
parseInt("11110", 2); // "30"
parseInt("u", 36); // "30"
我们需要一个在0到ffffff之间的十六进制数,也就是parseInt("ffffff", 16) == 16777215
,16777215正是2^24 - 1的值。
二进制中,每次在1的右面加0,实际就是在做2^n运算,n就是0的个数。
1 // 1 == 2^0
100 // 4 == 2^2
10000 // 16 == 2^4
1000000000000000000000000 // 16777216 == 2^24
左移运算 x << n
就是在二进制数 x 的右边添加 n 个 0,1 << 24
就是16777216的简便写法。
Math.random()
返回取值范围 [ 0 , 1 ) 内的伪随机数。
var a = Math.random()*2+1 //设置一个随机1到3 (取不到3) 的变量
Math.random()*(1<<24)
就可以得到一个 0 到 16777216之间的值。
但是Math.random
返回的是一个浮点数字,我们只需要整数部,这里使用了“~”操作符(按位取反操作)。
这里并不关心正负值,它利用“”按位操作丢弃小数部分。因此通过两次取反就可以得到纯整数部,我们还可以将“~”视为parseInt的简写:
var a = 12.34; // ~~a = 12
var b = -1231.8754; // ~~b = -1231
var c = 3213.000001; // ~~c = 3213
~~a == parseInt(a, 10); // true
~~b == parseInt(b, 10); // true
~~c == parseInt(c, 10); // true
如果你仔细看原文评论,你会知道使用 按位或 "|"操作符也可以去掉小数部分。
~~a == 0|a == parseInt(a, 10);
~~b == 0|b == parseInt(b, 10);
~~c == 0|c == parseInt(c, 10);
我们最终得到了一个 0 到 16777216之间的随机数,也就是需要的随机颜色,使用toString(16)
转换成16进制就可以运行了。
github:Addy Osmani,原文链接:arqex.com,翻译链接:ourjs.com