DOM 事件模型2:阻止冒泡,popover,轮播BUG解决

1从popover(点击别处关闭浮层)理解冒泡与捕获

PK8Pv4.png

当几个DIV嵌套,触发事件时,是先进行捕获阶段的触发,再进行冒泡阶段的触发的.
例如一个popover的例子
想要的效果是点击别处关闭浮层
如图:
PMWijg.png

demo链接:
http://js.jirengu.com/soyet/4/

PMWkuQ.png
点击时触发了console.log函数,说明触发了document的点击事件,可是为什么没有出现浮层呢?

因为两次addEventListener是没有加参数的,所以以冒泡阶段执行两个事件,当点击点我按钮,结果是依次触发点我按钮的click事件和document的click事件.所以没有想要效果
PMW3DJ.png

加上debugger后发现两个函数确实都执行了,
PMWJER.png

2阻止冒泡 event.stopPropagation()

Propagation翻译:传播
stopPropagation,停止传播,不要再告诉父母了,不要再往上执行冒泡事件了

示例代码:
http://js.jirengu.com/soyet/8...
PMWDDH.png
PMfpZ9.png

2.1解决BUG

但是出现一个bug.当我点击点我按钮,浮层不会消失,但是当我点击浮层,浮层还是会消失,我想让浮层被点击时也不消失,只是点击其他地方消失,该如何做呢?

示例代码:
http://js.jirengu.com/faquz/2...

PMfkRK.png
将阻止冒泡事件加在wrapper上,这样当冒泡执行到wrapper时,就不会再继续往上传播,即到wrapper就停止了

PMfoQO.png

2.2jQuery的一个BUG

PMhc1f.png

$(wrapper).on("click",false);
jQuery的添加 监听事件中,如果在后面加上一个参数false,那么相当于下面的代码

$(wrapper).on("click",function(e){
   e.preventDefault();
   e.stopPropagation();
});

示例代码如下:
http://js.jirengu.com/salar/1...

preventDefault 是另外一个相关的方法,它可以阻止事件触发后默认动作的发生。

即既阻止默认事件,又阻止冒泡事件.
但是这样会出现一个BUG.
因为给wrapper加了 e.preventDefault();组织了默认事件,所以input无法点击了,复选框无法选中,所以不要这样写
PMhXB4.png

正确写法如下
PM4S41.png
http://js.jirengu.com/pebok/1...

2.3内存问题,如何优化

假如页面中有很多popover,那么每个document都要添加监听点击事件.这样浪费内存
解决方法:不一直监听document,只有当popover出来的时候才监听,且只监听一次,当点击完document,就清除了监听事件.这样节省内存
PM4UCq.png
示例代码:http://js.jirengu.com/mivaf/2...

2.3.1引出另一个问题,

PM4rb4.png
实例代码:
http://js.jirengu.com/waral/2...
去掉阻止冒泡事件,按理来说,点击button,知识添加了document的点击事件,而为什么有触发了document的点击事件呢?

因为代码是按照同步执行的规则来的,同步事件
,即一步一步的执行,这一步没有完成,不会进行下一步.当点击了btn,会把点击事件添加到document,然后冒泡才继续往上执行.
图解:
PM44KO.png

解决方法:
让这个添加监听事件函数慢一点执行,等冒泡阶段走完再执行
PM4ORP.png

代码:
http://js.jirengu.com/madin/1...

接下来再证明这一点:
PM5iin.png
示例代码:
http://js.jirengu.com/kehut/2...

3冒泡可视化

示例代码
http://js.jirengu.com/wotoz/5...
实际上是一次解析完毕
PMHd2R.png

4轮播BUG解决

4.1 切换标签页setInterval不工作BUG

浏览器有一个BUG,当页面标签切换时,setInterval回不工作或间歇性工作.例如

每秒打印两次日期,当切换别的标签页,再切回来时发现,setInterval只打印了一次,说明setInterval间歇工作
PMbXkD.png

解决方法:

浏览器标签页被隐藏或显示的时候会触发visibilitychange事件.
visibilitychange--MDN
document.addEventListener("visibilitychange", function() {
  console.log( document.visibilityState );
});

当页面标签切换出去,document.visibilityState值为hidden,再切换回来值为visible

用法2:

document.addEventListener("visibilitychange", function() {
  console.log( document.hidden );
});

当页面标签切换出去,document.hidden 值为true,再切换回来值为false
示例代码:
http://js.jirengu.com/gejax/1/

PMqt39.png

修改轮播代码:

var timer = setInterval(()=>{
    makeImgLeft(getImgN(n))
        .one('transitionend',(e)=>{
            makeImgRight($(e.currentTarget));//当前元素
        });

    makeImgMid(getImgN(n+1));
    n+=1;
},1000);

document.addEventListener("visibilitychange", function() {
    if(document.hidden){
        clearInterval(timer);
    }else{
        timer = setInterval(()=>{
            makeImgLeft(getImgN(n))
                .one('transitionend',(e)=>{
                    makeImgRight($(e.currentTarget));//当前元素
            });

            makeImgMid(getImgN(n+1));
            n+=1;
        },1000);
    }
});

预览地址
完整代码地址


风彻
1.5k 声望142 粉丝