【JavaScript從入門到精通】第四課初探JavaScript魅力-04
第四課初探JavaScript魅力-04
style與className
<html> <head> <meta charset="utf-8"> <title>無標題文檔</title> <style> #div1 {width:200px; height:200px; border:1px solid black;} .box {background:red;} </style> <script> function toRed() { var oDiv=document.getElementById('div1'); oDiv.style.background='red'; } </script> </head> <body> <input type="button" value="變紅" onclick="toRed()" /> <div id="div1"></div> </body> </html>
這段代碼的作用不必多說,點擊變紅按鈕后,div1塊的背景顏色會變?yōu)榧t色。現(xiàn)在我們打開瀏覽器的控制臺(F12),選中Div1,觀察點擊前后的變化:
可以看到,JS對div1的樣式實際上是通過行間樣式的方法進行控制的。實際上,通過JS的style方法加入的樣式都是通過行間樣式來控制的,而且通過style也只能讀取到元素的行間樣式。
我們來看看style和class之間的關系。要闡明這兩者之間的關系,首先需要弄清楚css里的樣式優(yōu)先級。在css里,樣式的優(yōu)先級代表了css優(yōu)先執(zhí)行的代碼。樣式優(yōu)先級的順序如下(從高到低):
- 行間樣式
- ID
- class
- 標簽
- 通配符
行間樣式具有最高的優(yōu)先級。現(xiàn)在我們來看這個一個例子:
<html>
<head>
<meta charset="utf-8">
<title>無標題文檔</title>
<style>
#div1 {width:200px; height:200px; border:1px solid black;}
.box {background:red;}
</style>
<script>
function toRed()
{
var oDiv=document.getElementById('div1');
oDiv.className='box';
}
function toGreen()
{
var oDiv=document.getElementById('div1');
oDiv.style.background='green';
}
</script>
</head>
<body>
<input type="button" value="變紅" onclick="toRed()" />
<input type="button" value="變綠" onclick="toGreen()" />
<div id="div1"></div>
</body>
</html>
上述代碼先執(zhí)行toRed函數(shù)再執(zhí)行toGreen函數(shù),程序可以正常運行;但如果先執(zhí)行toGreen函數(shù)再執(zhí)行toRed函數(shù),toRed函數(shù)會失效。原因在于點擊toGreen函數(shù)后,background為green屬性的css添加到了行間,而點擊toRed函數(shù),雖然也能給元素添加含有background為red屬性的class,但因為行間樣式優(yōu)先級比class高,所以優(yōu)先執(zhí)行行間樣式的代碼。我們可以得到如下結論:對于同一元素的同一屬性,如果修改了其style,之后再修改其className不會再有效果。因此我們建議,對于同一個元素,在操作上保持一致性,要么只操作它的style,要么只操作它的className。
提取行間事件與匿名函數(shù)
我們之前使用的onclick="toGreen()"這一類寫法就被叫做行間事件。然而,在我們實際工作的時候,一個頁面通常是由多個人完成,如果將事件寫在行間有可能會出現(xiàn)編輯的時候事件被刪掉的情況。而且,當需要給大量元素增添功能相同的事件時,使用行間事件顯得太過麻煩和重復。若元素的數(shù)量不固定,使用行間事件更是對代碼無從下手。而采用提取行間事件的方法,可以很好地解決這些問題。
說到提取行間事件,我們首先得提到如何用JS給元素添加事件。可以看到,行間事件onclick的寫法讓onclick顯得很像一個屬性,那么是否可以通過操縱屬性的方法將行間事件寫到函數(shù)里呢?當然是可以的,我們將之前例子的一些代碼進行修改:
var oBtn=document.getElementById('btn1');
function abc(){
alert('a');
}
oBtn.onclick=abc;
效果和使用行間事件沒有任何區(qū)別。這就是最簡單的提取行間事件的方法。
在寫網(wǎng)頁代碼的時候,如果代碼量過大或者函數(shù)過多,取函數(shù)名是一件非常頭疼的事情。在JS里,提供了一種匿名函數(shù)的形式,這種寫法不用給函數(shù)取名,而函數(shù)體需要放在調用函數(shù)的地方。我們可以將上面的代碼改成如下形式:
var oBtn=document.getElementById('btn1');
oBtn.onclick=function () //匿名函數(shù)
{
alert('a');
};
實際工作中,大部分的事件都是通過這種匿名函數(shù)的方式完成的,這樣非常方便,不會出現(xiàn)忘記函數(shù)名的情況。
window.onload事件
JS代碼在瀏覽器執(zhí)行的時候,有一個特點:每讀一行,執(zhí)行一行。在我們上面的例子中,我們將script標簽放在了body里,程序可以正常執(zhí)行。但如果你試著將script標簽放在head標簽里,你會發(fā)現(xiàn)程序報錯。原因在于,當瀏覽器讀到oBtn.onclick這一行時,后面body的代碼還沒有被加載進來,因此實際上你是在給一個不存在的按鈕添加onclick事件,自然就會出錯了。如何解決這個問題呢?
這個問題可以用window.onload事件解決。這個事件代表的含義是,當頁面加載完成的時候發(fā)生。我們在前面的代碼外套加window.onload:
window.onload=function (){
var oBtn=document.getElementById('btn1');
oBtn.onclick=function ()
{
alert('a');
}
};
添加之后,window.onload內包裹的函數(shù)只在頁面加載結束后執(zhí)行,因此函數(shù)執(zhí)行的時候btn1已結被加載了進來,這樣程序就不會出錯了。
行為,樣式,結構三者分離
在前端領域來說,行為,樣式,結構三者分別對應著JavaScript,css和HTML,而將行為,樣式,結構三者分離,簡單來說,就是避免添加行間樣式和行間事件。我們之前采用提取行間事件的方法將寫成函數(shù)就是這個目的,在今后的代碼編寫中,也建議大家盡量遵守這個原則。
獲取一組元素
我們之前提到,如果頁面需要給大量元素添加事件,使用我們之前的寫法會讓代碼顯得非常繁雜重復。使用getElementsByTagName方法獲取元素可以避免這一點。和getElementById方法不同的是,getElementById一次只能獲取一個元素(因為id在HTML里不可重復),而getElementsByTagName一次可以獲取一組元素。
為了說明這個問題,我們再舉一個小例子:
<html>
<head>
<meta charset="utf-8">
<title>無標題文檔</title>
<style>
div {width:200px; height:200px; float:left; border:1px solid black; margin:10px;}
</style>
<script>
window.onload=function ()
{
var aDiv=document.getElementsByTagName('div');
alert(aDiv.length);
};
</script>
</head>
<body>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</body>
</html>
我們通過getElementsByTagName獲得了所有標簽名為div的元素,而此時aDiv不再是一個元素而是一個數(shù)組。數(shù)組的簡單概念可以理解為一堆元素的集合。數(shù)組有一個最簡單的屬性:length,代表了數(shù)組長度(元素個數(shù)),因此上面的例子中最后會彈出div塊的個數(shù)。因此結果如下:![]()
同樣的,如果我們想修改這些div的樣式,是否可以直接利用getElementsByTagName獲取后直接修改呢?:
var aDiv = getElementsByTagName('div');
aDiv.style.background = 'red';
這樣的寫法是會出錯的。原因在于在JS里,一次只能對一個元素的屬性進行設置,而aDiv是一個數(shù)組,內含多個元素,無法對其進行直接操作。為了對數(shù)組進行操作,我們需要了解如何獲得數(shù)組內的單個元素。我們如果將上面的代碼進行這樣的修改:
var aDiv = getElementsByTagName('div');
aDiv[0].style.background='red';
可以看到,第一個div塊變?yōu)榱思t色。aDiv[0]中的0被稱為下標,代表數(shù)組中元素的位數(shù),需要注意的是下標統(tǒng)一是從0開始,aDiv[0]代表了aDiv數(shù)組中的第一個元素。
var aDiv = getElementsByTagName('div');
aDiv[0].style.background='red';
aDiv[1].style.background='red';
aDiv[2].style.background='red';
aDiv[3].style.background='red';
這樣就能把4個div塊的顏色都進行改變,但設置元素樣式的代碼依舊非常繁瑣,如果存在100個這樣的div,是否就需要將這樣的代碼寫100次?實際上是不需要的,為了能夠把這些類似的代碼合并掉,我們需要用到循環(huán)。
循環(huán)
說到循環(huán),我們先來回憶一下我們學過的if語句。還記得if語句的格式如下:
if(條件){
語句1
}
else{
語句2
}
對于if語句來說,如果條件是成立的,會執(zhí)行一次語句1,否則執(zhí)行一次語句2。然而,如果我們想多次執(zhí)行語句1呢?采用循環(huán)的方式便可以讓一個語句進行多次執(zhí)行。 第一種循環(huán)(while循環(huán))的語句格式如下:
while(條件){
語句
}
對于while循環(huán)來說,只要條件成立,語句會一直執(zhí)行,直到條件不再成立。我們用例子說明:
var i = 0; //初始化
while (i < 5) { //條件
alert(i); //語句
i = i + 1 //自增
}
i=i+1的意思是將i的值加1再返回給自身,也就是說,循環(huán)每執(zhí)行一次,i的大小就增加1。執(zhí)行的結果如下:
當?shù)谝淮螆?zhí)行完畢后,i的值變?yōu)榱?,依然比5小,所以繼續(xù)執(zhí)行,這樣再反復四次后,i的值變?yōu)榱?,5=5,條件不再成立,所以跳出了循環(huán)。對于一個循環(huán),通常需要包含四個部分:初始化,條件,語句,自增。值得一提的是,表示自增的時候,我們通常用i++來代i=i+1這種比較復雜的寫法。
在很多情況下,使用while循環(huán)是一個比較麻煩的選擇,因此我們有了第二種更方便的循環(huán)語句:for循環(huán)。for循環(huán)的語句格式如下:
for(初始化;條件;自增){
語句
}
和while循環(huán)一樣,for循環(huán)也包含這四個部分,只不過格式上更為簡便。上面的代碼可以改為:
for(var i = 0; i < 5;i ++){
alert(i);
}
那么,回到我們的getElementsByTagName方法上來。通過循環(huán)的方式,我們可以很輕松的將代碼進行簡化:
var aDiv = getElementsByTagName('div');
for(i = 0;i < 4;i ++){
//i->0,1,2,3
aDiv[i].style.background='red';
}
這里還存在最后一個小問題,如果我的div個數(shù)發(fā)生了改變(例如郵箱,每個人郵箱里面的郵件個數(shù)都是不同的),而我在函數(shù)用i<4將div塊的個數(shù)定為4個,那么會產生HTML和JS代碼不一致的情況,每次執(zhí)行都需要修改JS。實際上,這個例子里的div個數(shù),就是aDiv這個數(shù)組的長度,因此我們可以使用用length屬性來解決這個問題。
var aDiv = getElementsByTagName('div');
for(i = 0;i < aDiv.length;i ++){
//i->0,1,2,3
aDiv[i].style.background='red';
}
這樣無論html代碼如何修改div塊的個數(shù)JS也可以自動適應了。
全選、反選、不選
全選、反選、不選是網(wǎng)頁經(jīng)常會用到的功能,它們分別是怎么實現(xiàn)的呢?
我們給網(wǎng)頁添加button和多個checkbox,希望通過button來控制checkbox的選中情況。根據(jù)我們前面所學的知識,我們應該采取如下思路:通過getElementById選中button,然后給button添加onclick事件,然后通過getElementsByTagName選中input標簽來操作checkbox。這里有一個小小的問題,因為checkbox和button屬性的標簽都是input,所以如果通過input標簽來進行元素選擇,會同時選中checkbox和button,產生一些問題。
這里可以采用一個小技巧解決這個問題。我們將所有checkbox放入一個id為div1的標簽中,然后在JS采用如下寫法:
var oDiv = document.getElementById('div1');
var aCh = oDiv.getElementById('input');
也就是說,getElementById前不一定是document,在本例中先選中了div1,再從div1中選中input,這樣就避免了選中button的情況。
在HTML中,控制checkbox選中情況的屬性為checked,同理在JS里,可以通過操縱checked屬性來改變checkbox的選中情況(選中時checked屬性為true,未選中時為false)。true/false在JS里被稱為布爾值,具體概念以后再講。
具體代碼如下:
<html>
<head>
<meta charset="utf-8">
<title>無標題文檔</title>
<script>
window.onload=function ()
{
var oBtn1=document.getElementById('btn1');
var oBtn2=document.getElementById('btn2');
var oBtn3=document.getElementById('btn3');
var oDiv=document.getElementById('div1');
var aCh=oDiv.getElementsByTagName('input');
oBtn1.onclick=function ()
{
for(var i=0;i<aCh.length;i++)
{
aCh[i].checked=true;
}
};
oBtn2.onclick=function ()
{
for(var i=0;i<aCh.length;i++)
{
aCh[i].checked=false;
}
};
oBtn3.onclick=function ()
{
for(var i=0;i<aCh.length;i++)
{
if(aCh[i].checked==true)
{
aCh[i].checked=false;
}
else
{
aCh[i].checked=true;
}
}
};
};
</script>
</head>
<body>
<input id="btn1" type="button" value="全選" /><br>
<input id="btn2" type="button" value="不選" /><br>
<input id="btn3" type="button" value="反選" /><br>
<div id="div1">
<input type="checkbox" /><br>
<input type="checkbox" /><br>
<input type="checkbox" /><br>
<input type="checkbox" /><br>
<input type="checkbox" /><br>
<input type="checkbox" /><br>
<input type="checkbox" /><br>
<input type="checkbox" /><br>
<input type="checkbox" /><br>
<input type="checkbox" /><br>
<input type="checkbox" /><br>
<input type="checkbox" /><br>
<input type="checkbox" /><br>
<input type="checkbox" /><br>
<input type="checkbox" /><br>
<input type="checkbox" /><br>
<input type="checkbox" /><br>
</div>
</body>
</html>





浙公網(wǎng)安備 33010602011771號