一次关于js事件出发机制反常的解决记录

起因:正常情况下我点击s2时是先弹出我是children,再弹出我是father,但是却出现了先弹出我是father,后弹出我是children的情况,这种情况是在和安卓app交互的h5页面中出现的,本地测试没有问题,但是在安卓打包的内嵌h5页面就出现了问题。简单化的代码先展示出来。

html代码如下

<div id="father" class="ss1">s1
    <div id="children" class="ss2">s2
    </div>
</div>

事件绑定如下

$(‘#father‘).on(‘click‘,function (e) {
   alert(‘我是father‘)
 })
$(‘#children‘).on(‘click‘,function (e) {
   alert(‘我是children‘)
   e.stopPropagation();
 })

借此问题,复习了一下js事件,先看一下几个定义

先来看事件注册

// IE以外的其他浏览器
// target :文档节点、document、window 或 XMLHttpRequest。
// type :字符串,事件名称,不含“on”,比如“click”、“mouseover”、“keydown”等。
// listener :实现了 EventListener 接口或者是 JavaScript 中的函数。
// useCapture :是否使用捕捉,一般用 false,事件触发时,会将一个 Event 对象传递给事件处理程序。

target.addEventListener(type,listener,useCapture);//添加
target.removeEventListener(type,listener,useCapture);//删除
// IE浏览器
// target :文档节点、document、window 或 XMLHttpRequest。
// type :字符串,事件名称,含“on”,比如“onclick”、“onmouseover”、“onkeydown”等。
// listener :实现了 EventListener 接口或者是 JavaScript 中的函数。

target.attachEvent(type, listener);//添加
target.detachEvent(type, listener);// 移除

兼容写法

兼容后的方法
var func = function(){};
//例:addEvent(window,"load",func)
function addEvent(elem, type, fn) {
    if (elem.attachEvent) {
        elem.attachEvent(‘on‘ + type, fn);
        return;
    }
    if (elem.addEventListener) {
        elem.addEventListener(type, fn, false);
    }
} 

//例:removeEvent(window,"load",func)
function removeEvent(elem, type, fn) {
    if (elem.detachEvent) {
        elem.detachEvent(‘on‘ + type, fn);
        return;
    }
    if (elem.removeEventListener) {
        elem.removeEventListener(type, fn, false);
    }
}

获取事件对象和事件源(触发事件的元素) 

function eventHandler(e){
     //获取事件对象
    e = e || window.event;//IE和Chrome下是window.event FF下是e
     //获取事件源
     var target = e.target || e.srcElement;//IE和Chrome下是srcElement FF下是target
 } 

事件委托

myTable.onclick = function () {
    e = e || window.event;
    var targetNode = e.target || e.srcElement;
    // 测试如果点击的是TR就触发
    if (targetNode.nodeName.toLowerCase() === ‘tr‘) {
        alert(‘You clicked a table row!‘);
    }
}

事件函数的解除绑定

和事件的绑定其实是相对应的,如果需要接触事件的绑定,运行对应的函数就可以了。如果是原生JS绑定则对应运行removeEventListener()和detachEvent()。

如果是jQuery的bind()和delegate()绑定,也是存在对应的解绑函数用以清除注册事件,比如unbind()和undelegate()。

看一个代码示例:

var EventUtil = {
    //注册
    addHandler: function(element, type, handler){
        if (element.addEventListener){
            element.addEventListener(type, handler, false);
        } else if (element.attachEvent){
            element.attachEvent("on" + type, handler);
        } else {
            element["on" + type] = handler;
        }
    },
    //移除注册
    removeHandler: function(element, type, handler){
        if (element.removeEventListener){
            element.removeEventListener(type, handler, false);
        } else if (element.detachEvent){
            element.detachEvent("on" + type, handler);
        } else {
            element["on" + type] = null;
        }
    }
};

再来看看事件流

几个概念

捕获阶段:事件对象通过目标的祖先从传播窗口到目标的父。这个阶段也被称为捕获阶段

目标阶段:本次活动对象到达事件对象的事件的目标。这个阶段也被称为目标阶段。如果事件类型指示事件不起泡,则在完成此阶段后,事件对象将停止。

冒泡阶段:事件对象通过目标的祖先中传播以相反的顺序,开始与目标的父和与所述结束窗口。这个阶段也被称为冒泡阶段

默认行为:事件通常由实现作为用户操作的结果分派,以响应任务的完成,或者在异步活动(例如网络请求)期间发信号通知进度。有些事件可以用来控制下一个实现可能采取的行为(或者撤销实现已经采取的行动)。这个类别中的事件被认为是可取消的,他们取消的行为被称为他们的默认行为

取消事件:可取消的事件对象可以与一个或多个“默认动作”相关联。要取消事件,请调用该preventDefault()方法。

一个图片

再上个小demo

<ul>
    <li>点我试试</li>
</ul>
<div id="s1" class="ss1">s1
    <div id="s2" class="ss2">s2</div>
</div>
var ul = document.getElementsByTagName(‘ul‘)[0];
var li = document.getElementsByTagName(‘li‘)[0];element.addEventListener(eventfunctionuseCapture)
document.addEventListener(‘click‘,function(e){console.log(‘document clicked‘)},true);//第三个参数为true使用捕获,false为冒泡,false为默认
ul.addEventListener(‘click‘,function(e){console.log(‘ul clicked‘)},true);
li.addEventListener(‘click‘,function(e){console.log(‘li clicked‘)},true);
//IE低版本兼容写法
li.attachEvent(‘onclick‘,function(event){
    debugger
    console.log(‘li clicked‘);
    event.cancelBubble=true;
});

s1.addEventListener(‘click‘,function () {
    console.log(‘s1 捕获方式‘)
},true)
s1.addEventListener(‘click‘,function () {
    console.log(‘s1 冒泡方式‘)
},false)
s2.addEventListener(‘click‘,function (e) {
    console.log(‘s2 捕获方式‘)
    // e.stopPropagation();
},true)
s2.addEventListener(‘click‘,function () {
    console.log(‘s2 冒泡方式‘)
},false)

点击li时,打印 依次为

ul clicked li clicked  

点击s1时,打印依次为

s1 捕获方式    s1 冒泡方式

点击s2时,打印依次为

s1 捕获方式 s2 捕获方式 s2 冒泡方式 s1 冒泡方式

处理事件冒泡和默认事件

1、e.preventDefault()

var a = document.getElementById("testA");
a.onclick =function(e){
    if(e.preventDefault){
        e.preventDefault();//
    }else{
        window.event.returnValue = false;//IE
    //注意:这个地方是无法用return false代替的
    //return false只能取消元素
    }
}

2、return false  javascript的return false只会阻止默认行为,而是用jQuery的话则既阻止默认行为又防止对象冒泡。

//原生js,只会阻止默认行为,不会停止冒泡
var a = document.getElementById("testA");
a.onclick = function(){
    return false;//当然 也阻止了事件本身
};
//既然return false 和 e.preventDefault()都是一样的效果,那它们有区别吗?当然有。
//仅仅是在HTML事件属性 和 DOM0级事件处理方法中 才能通过返回 return false 的形式组织事件宿主的默认行为。
1 //jQuery,既阻止默认行为又停止冒泡
2 $("#testA").on(‘click‘,function(){
3     return false;//当然 也阻止了事件本身
4 });

总结使用方法

当需要停止冒泡行为时

function stopBubble(e) {
    //如果提供了事件对象,则这是一个非IE浏览器
    if ( e && e.stopPropagation ){
        e.stopPropagation(); //因此它支持W3C的stopPropagation()方法
    }else{
        window.event.cancelBubble = true; //否则,我们需要使用IE的方式来取消事件冒泡
    }
}

当需要阻止默认事件时

function stopDefault( e ) {
    if ( e && e.preventDefault ){
        e.preventDefault(); //阻止默认浏览器动作(W3C)
    }else {
        window.event.returnValue = false; //IE中阻止函数器默认动作的方式
    }
    return false;
}

最后的解决方法:

让我们回顾一下最初的问题,可能部分浏览器把事件的useCapture默认为true,导致点击子元素时父元素的事件先响应了,于是我的办法是在父元素的事件里进行判断

比如容器为#a,动态插入的元素为#b,在#a上监听click事件,判断event.target.id是不是等于b即可,如果.bclass这种,以此类推。

我们经常能遇到阻止冒泡,但是阻止捕获一般不会遇到,因为浏览器一般默认就给我们阻止了,只能说什么情况都有啊,万事还是得考虑周全。

原文地址:https://www.cnblogs.com/wuyuchao/p/8309290.html

时间: 2024-11-05 14:37:17

一次关于js事件出发机制反常的解决记录的相关文章

这可能是最简明扼要的 js事件冒泡机制+阻止默认事件 讲解了

哎 js事件冒泡机制和阻止冒泡 阻止默认行为好像永远也整不清楚,记了忘 忘了记...醉了 这篇文章写完以后下次再忘记 就呼自己一巴掌,忘一次一巴掌 首先要明白两个概念--事件和事件流 事件指的是用户或浏览器自身执行的某种动作,又称为原始事件模型,例如onclick等 事件流指的是 从页面中接收事件的顺序,也就是说当一个事件产生时,这个事件的传播过程就叫做事件流. 事件冒泡: 从事件目标开始 一级级向上冒泡,到document为止--从里到外 IE 5:div--body--document; I

js事件循环机制辨析

?对于新接触js语言的人来说,最令人困惑的大概就是事件循环机制了.最开始这也困惑了我好久,花了我几个月时间通过书本,打代码,查阅资料不停地渐进地理解他.接下来我想要和大家分享一下,虽然可能有些许错误的地方,希望大家不吝赐教,感谢感谢. ?这是所涉及的知识点: 观察者模式 js的事件循环机制 js事件循环机制优缺点及与多线程的比较 观察者模式 ?js的事件循环机制是基于观察者模式的,而跟观察者模式相对应的是轮询,我们先来说说轮询的原理. ?我们将轮询映射在现实世界中即为:B不停到A的房间观察房间里

js事件线程机制和异步执行

浏览器的内核是多线程的,它们在内核制控下相互配合以保持同步,一个浏览器至少实现三个常驻线程:javascript引擎线程,GUI渲染线程,浏览器事件触发线程. javascript执行顺序:http://bbs.html5cn.org/thread-80116-1-1.html 1.javascript引擎是基于事件驱动单线程执行的,JS引擎一直等待着任务队列中任务的到来,然后加以处理,浏览器无论什么时候都只有一个JS线程在运行JS程序. 2.GUI渲染线程负责渲染浏览器界面,当界面需要重绘(R

js事件流机制冒泡和捕获

JavaScript与HTML之间的交互是通过事件实现的.事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间. 事件流 从页面中接收事件的顺序称为事件流. IE --> 事件冒泡流 Netscape --> 事件捕获流 查看源码:DOM2事件-捕获-冒泡 事件冒泡 IE的事件流叫做事件冒泡(event bubbling),即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档). 我们先来个简单的例子,这是HTML结构 <!DOCTYP

JS事件冒泡机制以及委托方法,以及vue中的stop

要理解事件冒泡机制,就得先了解事件. 浏览器是事件驱动型的,根据用户的行为触发不同的事件,根据事件执行相应的操作.我们较为熟悉的事件有三大类型:鼠标键盘事件.页面事件.表单相关事件. 鼠标键盘事件:onclick.ondbclick.onmousedown.onmouseup.onmouseover.onmousemove.onmouseout.onkeypress.onkeydown.onkeyup: 页面事件:onload.onunload.onresize.onerror.onabort:

JS事件委托机制简介

目的--为了减少对DOM的操作,使用事件委托. 理解--举例说明:有三个同事预计会在周一收到快递.为签收快递,有两种办法:一是三个人在公司门口等快递:二是委托给前台MM代为签收.现实当中,我们大都采用委托的方案(公司也不会容忍那么多员工站在门口就为了等快递).前台MM收到快递后,她会判断收件人是谁,然后按照收件人的要求签收,甚至代为付款.这种方案还有一个优势,那就是即使公司里来了新员工(不管多少),前台MM也会在收到寄给新员工的快递后核实并代为签收. 原理--事件委托是利用事件的冒泡原理来实现的

JS 事件冒泡、捕获。学习记录

作为一个转行刚到公司的新人,任务不多,这一周任务全部消灭,闲暇的一天也别闲着,悄悄的看起了书.今天写一下JS的事件冒泡.捕获. 也是今天看的内容有点多了,有些消化不了,就随手记录一下.纯属自我理解,如果有不对,还请指导提出,小弟一定改正. 好了,话不多说.那么事件冒泡是什么? 举个例子 ul > li > div > p . 这个时候你点击P,他会一层一层的往上执行,直到最后绑定事件的元素.假如我们绑定事件在ul上,那么点击P,他就会逐级往上走,直到找到绑定事件的ul也会触发事件,那么在

d3可视化实战04:事件绑定机制

首先说明,d3支持所有的JS事件——甚至其他代码的自定义事件.这里有一个列表,The MDN Event Reference, 包含了几乎所有浏览器创建的事件类型.大家有需要可以去查看. D3的事件绑定的语法,与jquery等其他类库用起来区别不大,都是object.on( event, listener )的形式.但是在具体实践中,我们经常会遇到给同一个对象绑定多个事件监听器的问题.这里就原生js.jquery和d3分别进行讨论. 一.原生JS的事件绑定 在探讨这个问题之前,我们首先需要看一下

Android6.0触摸事件分发机制解读

本篇博文是Android触摸事件分发机制系列博文的第一篇,带领大家从全局掌握Android触摸事件分发机制.特别声明的是,本源码解读是基于最新的Android6.0版本. (一)Android6.0源码解读之View点击事件分发机制 (二)Android6.0源码解读之ViewGroup点击事件分发机制 (三)Android6.0源码解读之Activity点击事件分发机制 为什么要解读触摸事件分发机制 1.掌握View事件分发机制 2.为解决View滑动冲突提供理论支持 3.了解Android最