JavaScript實現點擊隨機變色
事起緣由
6月21日晚,古哥給咱們科普頁面渲染機制、JS的一些性能優化和MV*架構,收益匪淺。在培訓現場,古哥請船長當場用原生JS實現點擊盒子隨機變 色。船長的編程思路讓人腦洞有點大開,Get到不少干貨。借著這個例子,古哥不斷灌輸各種性能優化、瀏覽器兼容寫法、代碼整潔等概念。想不到一個如此簡單 的例子竟有這么大的學問。于是培訓歸來當晚,當即打開電腦,把這個例子自己實現了一遍。于是便有了此文。
下面我來講講我是怎么做的。
一. 首先搭好HTML結構和CSS樣式
<!DOCTYPE html>
<html>
<head>
<title>changeColor</title>
<style>
.colorBox {
width: 200px;
height: 200px;
margin: 20px;
background-color : rgb(100, 200, 100);
cursor: pointer;
}
</style>
</head>
<body>
<div id="colorBox" class="colorBox"></div>
</body>
</html>
接下來肯定是要用JS控制DOM元素啦。
二. 創造隨機顏色生成器
首先,需要明確使用何種色彩模式。在HTML標準中,色彩模式有十六進制、RGB、HSL、RGBA、HSLA等。其中,HSL和HSLA不能兼容IE6-8。
1. 創建隨機數
因為顏色是隨機生成的,因此需要用到Math.random()函數。由于Math.random()生成0~1之間的隨機數(包括0不包括1), 有時并不能滿足我們的需求,因此可能需要乘除一個數。如果希望得到整數,需要對隨機數進行取整,可用Math.ceil()【向上取整】或 Math.floor()【向下取整】或Math.round()【四舍五入】,或者paseInt()。
舉個實用的栗子,如何獲得兩個數之間的隨機數:
function getRandom(min, max) {
return Math.round(Math.random()*(max - min) + min);
}
Math.random()(max – min) + min應該還是比較好理解的,用底數(min)加上隨機偏移量(Math.random()(max – min))就是隨機數的大小。
為了使隨機數看起來更隨機一些,建議使用Math.round()。因為譬如使用Math.ceil()取整的話,min能被娶到的幾率非常非常 小,只有Math.random()=0時才能取到。同理Math.floor()和paseInt()將永遠也取不到max值。
當然,JavaScript中的隨機數Math.random()并非真正意義上的隨機,只能算“偽隨機數”,這與它的產生算法有關,這里不展開討論。不過Math.random()應付一般的不那么精準的項目中已經夠用了。
2. 創建隨機顏色
其實使用哪一種色彩模式的實現方式差不多,只是字符串的拼接結果不一樣而已。
(1) 使用十六進制色彩模式
直接上代碼:
function randomColor() {
// 這里使用十六進制顏色值
var colorArr = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"];
var colorVal = "#";
for(i = 0; i < 6; i++) {
colorVal += colorArr[Math.round(15*Math.random())];
}
return colorVal;
}
(2) 使用RGB色彩模式
直接上代碼:
function randomColor() {
// 這里使用rgb顏色值
var colorVal = "rgb(";
for(i = 0; i < 3; i++) {
colorVal += Math.round(250*Math.random());
if (i < 2) {
colorVal += ",";
}
}
colorVal += ")";
return colorVal;
}
</code></pre>
當然,你還可以使用rgba定義它的透明度。
(3) 使用HSL色彩模式
直接上代碼:
function randomColor() {
// 這里使用HSL顏色值,但HSL不兼容IE6~8
// HSL(H, S, L),H的取值為0-360,S為0-100%,L為0-100%
// 在本例子中先設定好飽和度(S)和亮度(L),隨機變化色相(H)
var colorVal,
S = "50%",
L = "50%";
colorVal = "HSL(" + Math.round(360*Math.random()) + "," + S + "," + L + ")";
return colorVal;
}
3. 綁定樣式修改
這里需要修改盒子的background-color。我們可以直接操作<style>
標簽中的元素,不過最簡單的當然是直接在html中標簽的style屬性啦。
this.style.backgroundColor = randomColor();
4. 將使盒子變色的函數封裝
function changeColor() {
// 創造隨機顏色
function randomColor() {
// ...
}
this.style.backgroundColor = randomColor();
}
三. 給盒子綁定changeColor()事件
1. 獲取DOM元素
獲取DOM元素的幾種方法可以用document.getElementById()、document.getElementByName()、 document.getElementsByTagName()。當然還有高性能的document.querySelector(),并能兼容IE8 及其以上瀏覽器。
在這里,我使用原始的document.getElementById()。在一個頁面中經常需要獲取元素id的方法,所以可以考慮將其封裝成函數。見下:
// 獲取元素的id值
function getId(id) {
return document.getElementById(id);
}
2. 對事件進行綁定
(1) 使用基于DOM對象的屬性方式
最讓人容易想到的時間綁定方式就是ele.onclick = function(){},并且這種基于DOM對象的屬性方式能輕易地兼容IE6及其以上瀏覽器,非常好用。
colorBox.onclick = function() {
changeColor();
}
(2) 使用基于DOM對象的方法方式
綁定事件,addEventListener不能兼容IE6-8,因此IE6-8需要使用attachEvent,除了函數名、參數的不同,還有個關于 this指針的差異。在其它高版本瀏覽器中,綁定的事件處理函數被調用時,this指向事件綁定的object。而IE中,this指向window對 象,通過使用call或apply可以改變this指針的指向。
addEventListener語法:target.addEventListener(event, callback, useCapture);
attachEvent語法:target.attachEvent(event, fn);
另外,再來掰一掰addEventListener的事件流:
當一個事件發生時,分為三個階段:
a.捕獲階段: 從根節點開始順序而下,檢測每個節點是否注冊了事件處理程序。如果注冊了事件處理程序,并且 useCapture 為 true,則調用該事件處理程序;(IE 中無此階段);
b.目標階段: 觸發在目標對象本身注冊的事件處理程序,也稱正常事件派發階段;
c.冒泡階段: 從目標節點到根節點,檢測每個節點是否注冊了事件處理程序,如果注冊了事件處理程序,并且 useCapture 為false,則調用該事件處理程序;
一般地,先判斷使用addEventListener,后判斷attachEvent。這是因為addEventListener能兼容IE9以上 和其他絕大多數瀏覽器,而attachEvent只適用于IE,一般用之兼容IE6~8,而IE6~8的用戶較少,因此,應優先考慮先判斷 addEventListener以減短JS的渲染路徑,以達到絕大多數用戶的更好體驗。
// 事件綁定器
// 參數:target為DOM對象,event為事件名稱(不帶"on"),callback為接收事件處理的函數
function bindEvent(target, event, callback) {
if(window.addEventListener) {
return target.addEventListener(event, callback, false);
}else if(target.attachEvent) {
return target.attachEvent("on"+event, function() {
callback.apply(target);
});
}
}
四. 調用
在這之前,我已將使盒子變色的方法用changeColor()封裝,并將構建了一個事件綁定器bindEvent()。
上面折騰了辣么多都還木有見到效果,別急~
最后當然是優雅的一鍵調用啦。哈哈哈哈~o(^▽^)o~
var colorBox = getId("colorBox");
bindEvent(colorBox, "click", changeColor, false);
如果頁面中還有其他盒子需要變色,只需要優雅地調用一下bindEvent()即可完成擴展。
五. 性能優化
1 . 可以使用自執行函數將代碼塊進行封裝并創建偽命名空間,只要把自己所有的函數、對象和變量都寫在這個閉包函數內,那么外部就不能訪問,除非你允許。
2 . 在事件綁定中,古哥建議將事件綁定器用變量存儲,那樣每次調用事件綁定器時就不再需要重復判斷。古哥寫的事件綁定器代碼如下:
var w3c = document.dispatchEvent;
var bind = w3c?function(target,type,handler,phrase){
target.addEventListener(type,handler,!!phrase);
} : function(target,type,handler){
target.attachEvent && target.attachEvent("on"+type,function(){
handler.apply(target);
})
}
bind(box,"click",handleClick);
來自:http://www.dengzhr.com/js/424