关于事件对象event的一些整理

今天整理大红书上第13章事件,发现很多以前没注意到的东西,特此整理下来:

坑1:移除事件监听

我们知道addEventListener所添加的事件处理程序只能通过removeEventListener来移除,但是两次的参数必须一致,所以如果第二个参数是匿名函数就永远无法移除了:

        var btn = document.getElementById("myBtn");
        btn.addEventListener("click",function(){
            alert(this.id);
        },false);
        btn.removeEventListener("click",function(){
            alert(this.id);
        },false);//无效

此时这个事件监听并没有被移除,因为这两个匿名函数其实是完全不同的两个。

如果想要移除可以写成:

        var btn = document.getElementById("myBtn");        
        function alertId(){
            alert(this.id);
        }
        btn.addEventListener("click",alertId,false);
        btn.removeEventListener("click",alertId,false);//有效


坑2:执行顺序的不同

可以添加多个事件处理程序:

        var btn = document.getElementById("myBtn");
        btn.addEventLisrener("onclick",function(){
            alert("Clicked");
        });//先触发
        btn.addEventLisrener("onclick",function(){
            alert("又Clicked");
        });//后触发

但是IE情况下截然相反:

        var btn = document.getElementById("myBtn");
        btn.attchEvent("onclick",function(){
            alert("Clicked");
        });//后触发
        btn.attchEvent("onclick",function(){
            alert("又Clicked");
        });//先触发

支持IE事件处理程序的浏览器有IE和Opera

补充一下:ie事件处理程序的this指向的是window,DOM事件流中this永远等于currentTarget。

3.结合事件委托来看事件对象的属性

事件对象event包含“同创建它的特定事件相关的属性和方法”,其中有两个属性与事件委托紧密相关。

currentTarget  注册事件处理程序的那个元素(this始终等于此值) 

target  事件的真正目标 

        document.body.onclick = function(e){
            console.log(e.currentTarget === document.body);//true
            console.log(e.target === document.getElementById("myBtn"));//true          
        }

点击myBtn会发现打印出的结果都是true,具体流程是这样的:事件真正目标是myBtn按钮,但按钮上并未注册事件处理程序,随着click事件冒泡到document.body,他们发现document.body上注册了事件处理程序,事件才得到了处理。

阻止冒泡可以使用stopPropagation(),这个方法不止可以阻止冒泡还可以阻止捕获(对比cancelBubble只能取消冒泡,因为ie不支持事件捕获,这也解释了为啥attachEvent没有第三个参数)。注意我们还有个stopImmediatePropagation,比起stopPropagation(),他多做了一步:将事件对于当前节点的监听也取消了。笔试选择题里常常会把取消默认事件和阻止冒泡写在一起混淆视听,可以使用 preventDefault()来取消其默认行为,但能用这个方法的事件必须cancelable 属性设置为 true(这个事件表示是否可以取消,一般都是true不要担心)

eventPhase属性表示事件在事件流哪个阶段:

        btn.onclick = function(event){
            alert(event.eventPhase); //2 表示实际目标接收到事件
        };
        document.body.addEventListener("click", function(event){     
            alert(event.eventPhase); //1 表示捕获阶段
        }, true); //true - 事件句柄在捕获阶段执行
 
        document.body.onclick = function(event){     
            alert(event.eventPhase); //3 表示冒泡阶段
        }; 

千万不要忘记addEventListener第三个参数为true的时候表示在捕获阶段执行(这也是为啥大家都把他设成false)。

事件委托的优点是:

①减少事件注册节省内存:只需要在父节点绑定,其下子节点都能监听到。

②简化了节点更新时候的相应事件更新:不用在新增加的子节点上绑定事件;删除某事件也不用remove事件监听。

建议在浏览器卸载页面之前移除页面中的所有事件处理程序,不然他们就会留在内存中,这个时候事件委托的意义就体现出来了,敲好移除的。 


4.各种事件小李子

曾经出现过的一道面试题(不是我遇上的

自定义一个右键菜单,主要的思路还是右键点击会出现菜单,左键点击会消失,关键还是知道调用哪个事件。

   <div id="myDiv">
        Right click or Ctrl+click me to get a custom context menu.         
        Click anywhere else to get the default context menu
        <ul id="myMenu" style="position:absolute;visibility:hidden;background-color:silver">
            <li><a href="#">A</a></li>
            <li><a href="#">B</a></li>
            <li><a href="#">C</a></li>
        </ul>
    </div>
    <script>
        window.onload = function(){
            var oDiv = document.getElementById("myDiv");
            oDiv.addEventListener("contextmenu",function(e){
                var oMenu = document.getElementById("myMenu");
                oMenu.style.left = e.clientX+"px";
                oMenu.style.top = e.clientY+"px";
                oMenu.style.visibility = "visible";
                e.preventDefault();
            },false);
            oDiv.addEventListener("click",function(e){
                var oMenu = document.getElementById("myMenu");                
                oMenu.style.visibility = "hidden";
            },false);
        }
    </script>

e.preventDefault();是我认为的最重要的话,去掉默认的右键菜单。


在此处我们用到了visibility:visible 和visibility:hidden,尹深一下~

我们一直把visibility:visible看作opacity:1,把visibility:hidden看作opacity:0,但是在和transition结合使用的情况下其实是不一样的,让我们来看三个对比李子~

①只使用visibility

        #btn{
            visibility: visible;
            /*opacity: 1;*/
            transition: all 1s ease 3s;
        }
        #btn:hover {
            visibility: hidden;
            /*opacity: 0;*/
        }

没有淡入淡出效果,在3s后立刻消失。

②只使用opacity

可以实现淡入淡出效果。此时我们在js中为btn添加一个onclick的事件处理程序。

        oBtn.onclick = function(){
            alert("疼死我了");
        }

会发现在btn消失之后我们依然可以点击这个按钮并显示“疼死我了”

③既使用visibility又使用opacity

可以实现淡入淡出效果的同时,加在btn上的事件随着btn的消失也没办法触发了。


HTML5当中有一个新的API——visibilityState,用于记录当前标签页是否处于“激活状态”。当我们没有观看某个标签页时,这个标签页上的广告啊视频啊幻灯片小动画啥的可以先不用加载,这样既减小了服务器压力,毕竟用户不占用带宽了嘛,也可以节省客户端的内存。

document.addEventListener( "visibilitychange" , function(){}) 我们对于这个事件进行监听,后面是相应的事件处理程序。

            var div = document.getElementById("parent");
            document.addEventListener('visibilitychange',function(){
                if(document.hidden){
                    div.style.animationPlayState = 'paused';
                }else{
                    div.style.animationPlayState = 'running';
                }
            })

上面这段代码说的是当页面处于背景标签页或者最小化状态时document.hidden的情况下,暂停运动;否则继续运动。

一般只用document.hidden(表示背景标签页或者最小化)以及document.visible(表示前景标签页没有最小化)两种状态。

此处我们的css代码为:

        #parent {
            width: 300px;
            height: 300px;
            background: red;
            animation: loop 2s alternate infinite linear;
        }
        @keyframes loop {
            0% {
                border-radius: 30px;
            }
            100% {
                border-radius: 150px;
            }
        }

可以得到在30到150之间来回无限变化的边圆,非常平滑,而且我们可以控制它的暂停与开始,使用object.style.animationPlayState()即可。

我曾自己写了一个js代码表示在30到150之间来回无限变化的边圆,不平滑,也许这就是css的好处吧,因为设置了linear线性变化嘛。而且js代码还要判断方向,但在css中一个alternate就解决了。

附上js代码(比比css节省了多少事):

            var count = 1;
            setInterval(function(){
                var oDiv = document.getElementById("parent");
                var radius = window.getComputedStyle(oDiv)["borderRadius"];
                if(count===0){
                    oDiv.style.borderRadius = parseInt(radius)-10+'px';
                    if(radius==="30px"){
                        count = 1;
                    }
                }else{
                    oDiv.style.borderRadius = parseInt(radius)+10+'px';
                    if(radius==="150px"){
                        count = 0;
                    }
                }   
            },100);

完毕~

猜你喜欢

转载自blog.csdn.net/weixin_40322503/article/details/80043275