DOM事件之捕获、冒泡

DOM 0 知识点

<script>
    function print(){
        console.log(1)
    }
    
    X.onclick = print;  //是对的
    Y.onclick = print();
    Z.onclick = print.call();
</script>

<button id='X' onclick='print'>A</button>
<button id='Y' onclick='print()'>B</button>     //是对的
<button id='Z' onclick='print.call()'>C</button>    //是对的

HTML 中onclick = '要执行的代码',一旦用户点击,浏览就eval('要执行的代码'),这里不是属性,不是函数,是一段代码。
JavaScript 中,一旦用户点击,浏览器就执行X.onclick.call(X,{}),意思是onclick是一个函数属性,而print是一个属性,因为它的类型是对象;但下面的print()的类型是undefined
所以在HTML 中必须传递一个要执行的代码,JavaScript 中必须传递一个函数

DOM 2 知识点

<button id='xxx'>A<button>
xxx.addEventListener('click',function(){
    console.log(1)
})

xxx.onclick = function(){
    console.log(2)
}

那它们两个的区别是啥呢?
xxx.onclick = function(){}只是一个属性,所以它是唯一的,如果这时候你要绑定2个onclick事件就麻烦了。
xxx.addEventListener()它是一个队列,先进先出,就是说先绑定的先触发。所以它叫做事件监听队列,这里是排队,xxx拥有一个队列叫做eventlisteners,你不能直接访问它,但你可以通过addEventListener去排个队,如果用户点击了,就先触发排在第一位的函数,排在后面的一次触发。队列的实质是数组。既然有入队,那是不是也有出队:

function f1(){
    console.log(1);
}

function f2(){
    console.log(2);
}

function f1(){
    console.log(3);
}

xxx.addEventListener('click',f1);
xxx.addEventListener('click',f2);
xxx.removeEventListener('click',f1);
xxx.addEventListener('click',f3);
xxx.removeEventListener('click',f3);

最后的结果就是打印:2。
f1 在排队的过程中移除了,f3 刚进入队列就移除了。

前面写轮播的时候用了one事件,它内部是怎样的呢?

function f1(){
    console.log(1);
    xxx.removeEventListener('click',f1);
}
xxx.addEventListener('click',f1);

one在函数处理时的最后一句加上离开队列语句,on就是没有出队这句的,也就是说一直会执行。

JS事件中的冒泡和捕获

捕获事件:事件从最外层父元素到最里层子元素的顺序触发,叫做捕获事件,果document > html > body > div > p > button

冒泡事件:正好和捕获事件相反,事件从最里层子元素到最外层父元素的顺序触发,叫做冒泡事件,如:button > p > div > body > html > document

DOM 2 中规定了同时支持捕获事件和冒泡事件,用addEventListener()方法绑定一个事件处理函数,其语法:
target.addEventListener(type, listener, useCapture);
type:表示监听事件类型的字符串,如clcik,前面没有on
listener:表示监听的对象或者一个函数
useCapture:表示是否使用捕获,接受一个布尔值,true是触发捕获事件,不写默认false触发用冒泡事件。

事件在默认执行的过程中是先捕获后冒泡,第三个参数只是让它在什么状态下触发。如果一个节点捕获和冒泡事件同时存在,谁在前谁先执行,和事件无关。

<div id="s1">s1
    <div id="s2">s2</div>
</div>
<script>
    s1.addEventListener("click",function(e){
        console.log("s1 冒泡事件");         //4️⃣  
    },false);
    s2.addEventListener("click",function(e){
        console.log("s2 冒泡事件");         //2️⃣
    },false);
            
    s1.addEventListener("click",function(e){
        console.log("s1 捕获事件");         //1️⃣
    },true);
            
    s2.addEventListener("click",function(e){
        console.log("s2 捕获事件");         //3️⃣
    },true);
</script>

当我点击在s2上面,触发顺序是s1捕获事件 > s2冒泡事件 > s2捕获事件 > s1冒泡事件

事件代理:事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件。这种方法叫做事件的代理(delegation)。

<ul id="colors">
    <li>red</li>
    <li>yellow</li>
    <li>blue</li>
    <li>green</li>
    <li>black</li>
    <li>white</li>
</ul>
<script>
    var ul = document.querySelector('ul');
    
    ul.addEventListener('click', function (event) {
      if (event.target.tagName.toLowerCase() === 'li') {
        // some code
      }
    });
</script>

来看一个具体例子:获取li里面的文本,用事件流方法

var ul = document.querySelector('ul');
ul.addEventListener('click',showColor,false);
function showColor(e){
    var x = e.target;
    if(x.nodeName.toLowerCase() === 'li'){
        console.log('The color is ' + x.innerHTML);
    }
}

如果不使用事件代理,要获取li里面的文本应该怎么弄呢?老方法是获取到所有子元素li,遍历它就可以了

var colors = color-list.children
for(var i=0;i<colors.length;i++){                          
    colors[i].addEventListener('click',showColor,false);
};
function showColor(e){
    var x = e.target;
    console.log("The color is " + x.innerHTML);
};

阻止事件不再传播,可以使用事件对象的stopPropagation()方法,但不会彻底消除事件,如果说绑定多个事件的话。
stopImmediatePropagation()方法,绑定的其他事件也将不会执行。

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

推荐阅读更多精彩内容

  •   JavaScript 与 HTML 之间的交互是通过事件实现的。   事件,就是文档或浏览器窗口中发生的一些特...
    霜天晓阅读 3,426评论 1 11
  • 事件是一种异步编程的实现方式,本质上是程序各个组成部分之间的通信。DOM支持大量的事件,本节介绍DOM的事件编程。...
    周花花啊阅读 579评论 0 3
  • Dom事件 事件是一种异步编程的实现方式,本质上是程序各个组成部分之间的通信。DOM支持大量的事件 (一) Eve...
    woow_wu7阅读 1,714评论 0 1
  • 事件是一种异步编程的实现方式,本质上是程序各个组成部分之间的通信。DOM支持大量的事件,本节介绍DOM的事件编程。...
    许先生__阅读 878评论 0 3
  • 背景知识 什么是事件?直观的说就是网页上发生的事情,大部分是指用户的鼠标动作和键盘动作,如点击、移动鼠标、按下某个...
    吧啦啦小汤圆阅读 1,773评论 2 15