從零開始學(xué)習(xí)javascript項(xiàng)目(2)
任務(wù)描述
- 讀取頁面中id為source的列表切油,提取城市以及對(duì)應(yīng)的空氣質(zhì)量
- 把數(shù)據(jù)排序以后,在resort列表中按照順序顯示出來
<ul id="source">
<li>北京空氣質(zhì)量:<b>90</b></li>
<li>上杭蛉恚空氣質(zhì)量:<b>70</b></li>
<li>天津空氣質(zhì)量:<b>80</b></li>
<li>廣州空氣質(zhì)量:<b>50</b></li>
<li>深圳空氣質(zhì)量:<b>40</b></li>
<li>福州空氣質(zhì)量:<b>32</b></li>
<li>成都空氣質(zhì)量:<b>90</b></li>
</ul>
<ul id="resort">
<!--
<li>第一名:北京空氣質(zhì)量:<b>90</b></li>
<li>第二名:北京空氣質(zhì)量:<b>90</b></li>
<li>第三名:北京空氣質(zhì)量:<b>90</b></li>
-->
</ul>
<button id="sort-btn">排序</button>
任務(wù)規(guī)劃
為了完成這個(gè)任務(wù),我們需要分成三個(gè)部分來完成這個(gè)動(dòng)作
- 按下button的時(shí)候觸發(fā)動(dòng)作
- 抓取頁面上的列表到一個(gè)數(shù)組里面
- 把排序后的數(shù)組通過操作DOM使得新數(shù)組append到新的列表里面
綁定按鈕動(dòng)作與事件監(jiān)聽
和之前提到的一樣述暂,對(duì)于按鈕這個(gè)事件的觸發(fā)痹升,需要一個(gè)監(jiān)聽函數(shù)。首先使用抓取按鈕的DOM
var sort_btn = document.getElementById('sort-btn');
再對(duì)這個(gè)元素進(jìn)行監(jiān)聽動(dòng)作畦韭。
關(guān)于事件監(jiān)聽疼蛾,詳細(xì)點(diǎn)這里。如果不想看那么多艺配,可以看下面的精簡版察郁。
簡單的來說js的事件監(jiān)聽有三種方法
- element.addEventListener(type, listener[, useCapture]); // IE6~8不支持
- element.attachEvent(’on’ + type, listener); // IE6~10,IE11不支持
- element[’on’ + type] = function(){} // 所有瀏覽器
舉個(gè)栗子:
function cb() { console.log(1); }
element.addEventListener('click', cb, false);
element.attachEvent('onclick', cb);
element.onclick = cb;
type
:事件類型
listener
:事件觸發(fā)后的回調(diào)函數(shù)
useCapture
:是否使用捕獲转唉,如果值為true皮钠, useCapture 表示用戶希望發(fā)起捕獲。 在發(fā)起捕獲之后酝掩, 只要Dom子樹下發(fā)生了該事件類型鳞芙,都會(huì)先被該事件監(jiān)聽器捕獲,然后再被派發(fā)到Dom子樹中的事件監(jiān)聽器中期虾。并且向上冒泡的事件不會(huì)觸發(fā)那些發(fā)起捕獲的事件監(jiān)聽器原朝。 useCapture 默認(rèn)值為false
。
addEventListener
是W3C工作組在DOM Level 2開始引入的一個(gè)注冊(cè)事件監(jiān)聽器的方法镶苞;而在此之前喳坠,傳統(tǒng)的事件監(jiān)聽方法是通過element[’on’ + type]
的方式來注冊(cè)的。它們兩之間的主要區(qū)別是茂蚓,element[’on’ + type]
的方式無法使用事件捕獲壕鹉,并且element[’on’ + type]
不支持對(duì)同一個(gè)元素的同一個(gè)事件注冊(cè)多個(gè)事件監(jiān)聽器。如下面的例子所示聋涨,元素被點(diǎn)擊后只會(huì)輸出1晾浴,而不會(huì)輸出0和1.
element.onclick = function(){ console.log(0); }
element.onclick = function(){ console.log(1); }
看完我的解釋,是不是更加不明白了牍白?沒關(guān)系脊凰,趕緊點(diǎn)擊這里。 回過頭好好看一下好了茂腥。
淺談事件的捕獲和冒泡
對(duì)于所有中國人來說狸涌,有一個(gè)四字魔咒是永遠(yuǎn)繞不開的切省。只要有人對(duì)你說出這四個(gè)字,你就能中邪般地買票去最坑爹的景點(diǎn)帕胆、玩命爬上最艱險(xiǎn)的山峰朝捆、吃下最難吃的餐館飯菜…這四個(gè)字就是———來都來了。
所以懒豹,既然看到這了芙盘,我就帶你們?nèi)チ私庖稽c(diǎn)更深入的知識(shí)吧,畢竟來都來了 歼捐。
事件
javascript使用的是異步事件模型何陆,如果你寫過verilog,那么對(duì)這個(gè)概念應(yīng)該會(huì)比較熟悉豹储,而且javascript中的異步事件是基于觸發(fā)器的贷盲,也就是說你不必考慮異步時(shí)鐘域里面的數(shù)據(jù)傳輸而產(chǎn)生的亞穩(wěn)態(tài)和計(jì)算數(shù)據(jù)傳輸?shù)膸挕.惒绞录脑谟谥灰褂脮r(shí)間處理函數(shù)注冊(cè)一個(gè)回調(diào)函數(shù)剥扣,一旦事件觸發(fā)巩剖,就會(huì)立刻執(zhí)行回調(diào)函數(shù)。
DOM事件流的階段
所謂的事件流钠怯,就是事件在處理事件傳播過程中的順序佳魔,根據(jù)W3C模型的定義,這個(gè)傳播過程分別是捕獲階段晦炊,目標(biāo)階段鞠鲜,冒泡階段。事件階段存在的意義子啊與 當(dāng)我們?cè)谝粋€(gè)元素里面潛逃另外一個(gè)元素断国,并且這兩者都綁定了一個(gè)onClink事件贤姆,就像下面這樣
+-----------------+
| event1 |
| +-----------+ |
| | event2 | |
| +-----------+ |
| |
+-----------------+
(效果來自這里不是閑的蛋疼不要嘗試,不過畫點(diǎn)簡單的東西還是很給力的)稳衬。當(dāng)點(diǎn)擊事件發(fā)生的時(shí)候霞捡,哪一個(gè)先被觸發(fā),執(zhí)行的順序是什么薄疚?W3C模型采用的是一種先捕獲再冒泡的的方式碧信,大概就像下面這樣的。
/ \\
+----------------| |--| |----------------+
| element1 | | | | |
| +------------| |--| |----------+ |
| |element2 \\ / | | | |
| +------------------------------+ |
| W3C event model |
+----------------------------------------+
? 我們以一個(gè)例子來說明這種流程
<div id = "s1"> s1
<div id = "s2">s2</div>
</div>
<script>
s1.addEventListener("click",function(evt){
console.log("s1捕獲模式");
},true);
s2.addEventListener("click",function(evt){
console.log("s2捕獲模式");
},true);
s1.addEventListener("click",function(evt){
console.log("s1冒泡模式");
},false);
s2.addEventListener("click",function(evt){
console.log("s2冒泡模式");
},false);
</script>
結(jié)果如下
s1捕獲模式
s2捕獲模式
s2冒泡模式
s1冒泡模式
我們可以通過這個(gè)例子看到街夭,事件傳播的過程根據(jù)addEventListener方法設(shè)置的第三個(gè)參數(shù)確定捕獲的模式砰碴。在捕獲階段,事件到達(dá)事件目標(biāo)之前板丽,事件對(duì)象必須從windows經(jīng)過目標(biāo)的祖先節(jié)點(diǎn)傳播到時(shí)間目標(biāo)衣式,在這個(gè)階段注冊(cè)的事件監(jiān)聽器在到達(dá)目標(biāo)之前必須先處理事件。在目標(biāo)階段檐什,事件對(duì)象到達(dá)事件目標(biāo)碴卧,該階段的事件監(jiān)聽器就會(huì)對(duì)其進(jìn)行處理。最后就是冒泡階段乃正,事件對(duì)象以一個(gè)與捕獲階段相反的方向經(jīng)過祖節(jié)點(diǎn)傳播到window住册。在這個(gè)階段注冊(cè)的事件監(jiān)聽器會(huì)對(duì)相應(yīng)的冒泡時(shí)間進(jìn)行處理。
這樣就很清楚了瓮具。我再貼一張官方圖片:
如果你看不到上面的圖片荧飞,那么高清無碼大圖在這里 。當(dāng)然名党,我們也可以使用stopPropagation這個(gè)函數(shù)來停止事件的傳播叹阔,這里就不展開了。如果你有興趣的話传睹,可以研究一下關(guān)于IE對(duì)于事件捕獲的操作方法耳幢,通過監(jiān)聽父節(jié)點(diǎn)而不是監(jiān)聽父節(jié)點(diǎn)下面的每一個(gè)子節(jié)點(diǎn)來節(jié)約瀏覽器的資源,通過關(guān)閉冒泡和捕獲使函數(shù)的執(zhí)行互不干擾而節(jié)約瀏覽器的資源等等欧啤。
回歸主線
好了睛藻,說了這么多。我們?cè)谧约旱捻?xiàng)目里面需要用到的大概就是這么一句話
var sort_btn = document.getElementById('sort-btn');
sort_btn.addEventListener('click',function(){btnHandle()},false);
抓取列表元素到數(shù)組
這就是簡單的操作DOM的內(nèi)容了邢隧,我們的目標(biāo)是把城市和數(shù)字存到一個(gè)個(gè)的鍵值對(duì)中店印。
//函數(shù)應(yīng)該這么寫
function getData(){
var data = document.getElementById('source').getElementByTagName('li');
var a = [];
var city;
var num;
for(var i=0; i<data.length; i++){
city = data[i].innerHTML.substring(0,data[i].innerHTML.indexOf('空'));
num = data[i].getElementByTagName('b')[0].innerHTML;
a.push([city,num]);
}
return a;
}
- innerHTML不僅可以修改HTML元素還可以把元素內(nèi)容返回出來。
- substring用于提取字符串中介于兩個(gè)指定下標(biāo)之間的字符倒慧。其內(nèi)容是從 start 處到 stop-1 處的所有字符
- indexOf() 方法可返回某個(gè)指定的字符串值在字符串中首次出現(xiàn)的位置
對(duì)列表元素進(jìn)行排序
這一部分也很簡單按摘,教科書一般的排序方式。
function sortAqiData(data){
data.sort(function(a,b){
return (a[1]-b[1]);
})
}
通過操作DOM使排序后的數(shù)據(jù)顯示出來
function render(data){
var resort = document.getElementById('resort');
resort.innerHTML = '';
for(var i=0; i< data.length; i++){
var node = document.creatElement('li');
var html = '第'+(i+1)+'名:'+data[i][0]+'空氣質(zhì)量:<b>'+data[i][1]+'</b>'纫谅;
node.innerHTML = html;
resort.appendChild(node);
}
}
這樣炫贤,一個(gè)簡單的交互功能就算完成了。