从零开始学习javascript项目(2)
任务描述
- 读取页面中id为source的列表,提取城市以及对应的空气质量
- 把数据排序以后,在resort列表中按照顺序显示出来
<ul id="source">
<li>北京空气质量:<b>90</b></li>
<li>上海空气质量:<b>70</b></li>
<li>天津空气质量:<b>80</b></li>
<li>广州空气质量:<b>50</b></li>
<li>深圳空气质量:<b>40</b></li>
<li>福州空气质量:<b>32</b></li>
<li>成都空气质量:<b>90</b></li>
</ul>
<ul id="resort">
<!--
<li>第一名:北京空气质量:<b>90</b></li>
<li>第二名:北京空气质量:<b>90</b></li>
<li>第三名:北京空气质量:<b>90</b></li>
-->
</ul>
<button id="sort-btn">排序</button>
任务规划
为了完成这个任务,我们需要分成三个部分来完成这个动作
- 按下button的时候触发动作
- 抓取页面上的列表到一个数组里面
- 把排序后的数组通过操作DOM使得新数组append到新的列表里面
绑定按钮动作与事件监听
和之前提到的一样,对于按钮这个事件的触发,需要一个监听函数。首先使用抓取按钮的DOM
var sort_btn = document.getElementById('sort-btn');
再对这个元素进行监听动作。
关于事件监听,详细点这里。如果不想看那么多,可以看下面的精简版。
简单的来说js的事件监听有三种方法
- element.addEventListener(type, listener[, useCapture]); // IE6~8不支持
- element.attachEvent(’on’ + type, listener); // IE6~10,IE11不支持
- element[’on’ + type] = function(){} // 所有浏览器
举个栗子:
function cb() { console.log(1); }
element.addEventListener('click', cb, false);
element.attachEvent('onclick', cb);
element.onclick = cb;
type
:事件类型
listener
:事件触发后的回调函数
useCapture
:是否使用捕获,如果值为true, useCapture 表示用户希望发起捕获。 在发起捕获之后, 只要Dom子树下发生了该事件类型,都会先被该事件监听器捕获,然后再被派发到Dom子树中的事件监听器中。并且向上冒泡的事件不会触发那些发起捕获的事件监听器。 useCapture 默认值为false
。
addEventListener
是W3C工作组在DOM Level 2开始引入的一个注册事件监听器的方法;而在此之前,传统的事件监听方法是通过element[’on’ + type]
的方式来注册的。它们两之间的主要区别是,element[’on’ + type]
的方式无法使用事件捕获,并且element[’on’ + type]
不支持对同一个元素的同一个事件注册多个事件监听器。如下面的例子所示,元素被点击后只会输出1,而不会输出0和1.
element.onclick = function(){ console.log(0); }
element.onclick = function(){ console.log(1); }
看完我的解释,是不是更加不明白了?没关系,赶紧点击这里。 回过头好好看一下好了。
浅谈事件的捕获和冒泡
对于所有中国人来说,有一个四字魔咒是永远绕不开的。只要有人对你说出这四个字,你就能中邪般地买票去最坑爹的景点、玩命爬上最艰险的山峰、吃下最难吃的餐馆饭菜…这四个字就是———来都来了。
所以,既然看到这了,我就带你们去了解一点更深入的知识吧,毕竟来都来了 。
事件
javascript使用的是异步事件模型,如果你写过verilog,那么对这个概念应该会比较熟悉,而且javascript中的异步事件是基于触发器的,也就是说你不必考虑异步时钟域里面的数据传输而产生的亚稳态和计算数据传输的带宽。异步事件的在于只要使用时间处理函数注册一个回调函数,一旦事件触发,就会立刻执行回调函数。
DOM事件流的阶段
所谓的事件流,就是事件在处理事件传播过程中的顺序,根据W3C模型的定义,这个传播过程分别是捕获阶段,目标阶段,冒泡阶段。事件阶段存在的意义子啊与 当我们在一个元素里面潜逃另外一个元素,并且这两者都绑定了一个onClink事件,就像下面这样
+-----------------+
| event1 |
| +-----------+ |
| | event2 | |
| +-----------+ |
| |
+-----------------+
(效果来自这里不是闲的蛋疼不要尝试,不过画点简单的东西还是很给力的)。当点击事件发生的时候,哪一个先被触发,执行的顺序是什么?W3C模型采用的是一种先捕获再冒泡的的方式,大概就像下面这样的。
/ \\
+----------------| |--| |----------------+
| element1 | | | | |
| +------------| |--| |----------+ |
| |element2 \\ / | | | |
| +------------------------------+ |
| W3C event model |
+----------------------------------------+
我们以一个例子来说明这种流程
<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>
结果如下
s1捕获模式
s2捕获模式
s2冒泡模式
s1冒泡模式
我们可以通过这个例子看到,事件传播的过程根据addEventListener方法设置的第三个参数确定捕获的模式。在捕获阶段,事件到达事件目标之前,事件对象必须从windows经过目标的祖先节点传播到时间目标,在这个阶段注册的事件监听器在到达目标之前必须先处理事件。在目标阶段,事件对象到达事件目标,该阶段的事件监听器就会对其进行处理。最后就是冒泡阶段,事件对象以一个与捕获阶段相反的方向经过祖节点传播到window。在这个阶段注册的事件监听器会对相应的冒泡时间进行处理。
这样就很清楚了。我再贴一张官方图片:
如果你看不到上面的图片,那么高清无码大图在这里 。当然,我们也可以使用stopPropagation这个函数来停止事件的传播,这里就不展开了。如果你有兴趣的话,可以研究一下关于IE对于事件捕获的操作方法,通过监听父节点而不是监听父节点下面的每一个子节点来节约浏览器的资源,通过关闭冒泡和捕获使函数的执行互不干扰而节约浏览器的资源等等。
回归主线
好了,说了这么多。我们在自己的项目里面需要用到的大概就是这么一句话
var sort_btn = document.getElementById('sort-btn');
sort_btn.addEventListener('click',function(){btnHandle()},false);
抓取列表元素到数组
这就是简单的操作DOM的内容了,我们的目标是把城市和数字存到一个个的键值对中。
//函数应该这么写
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元素还可以把元素内容返回出来。
- substring用于提取字符串中介于两个指定下标之间的字符。其内容是从 start 处到 stop-1 处的所有字符
- indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置
对列表元素进行排序
这一部分也很简单,教科书一般的排序方式。
function sortAqiData(data){
data.sort(function(a,b){
return (a[1]-b[1]);
})
}
通过操作DOM使排序后的数据显示出来
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]+'空气质量:<b>'+data[i][1]+'</b>';
node.innerHTML = html;
resort.appendChild(node);
}
}
这样,一个简单的交互功能就算完成了。