从零开始学习javascript项目(2)——事件的监听、捕获和冒泡

从零开始学习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);
    }
}

这样,一个简单的交互功能就算完成了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,047评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,807评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,501评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,839评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,951评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,117评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,188评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,929评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,372评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,679评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,837评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,536评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,168评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,886评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,129评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,665评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,739评论 2 351

推荐阅读更多精彩内容

  • 以下文章为转载,对理解JavaScript中的事件处理机制很有帮助,浅显易懂,特分享于此。 什么是事件? 事件(E...
    jxyjxy阅读 3,030评论 1 10
  • (续jQuery基础(1)) 第5章 DOM节点的复制与替换 (1)DOM拷贝clone() 克隆节点是DOM的常...
    凛0_0阅读 1,324评论 0 8
  • 事件是一种异步编程的实现方式,本质上是程序各个组成部分之间的通信。DOM支持大量的事件,本节介绍DOM的事件编程。...
    周花花啊阅读 593评论 0 3
  • 现在的孩子独生子女居多,所以家长对孩子宠爱有加。真象对待小皇帝一般。含在嘴里怕化了,捧在手里怕掉了。随着时间的推移...
    光明自在行阅读 567评论 2 6
  • 正常如你我的普通人,也许想的最多的就是怎么能多拿些工资;或者工作上的一堆破事让自己牢骚满腹,天天抱怨个没完没了...
    静小酥阅读 323评论 0 0