• JavaScript--事件绑定及深入(26)


    // 事件绑定分为两种:

    // 一种是传统事件绑定(内联模型/脚本模型);上一章内容;

    // 一种是现代事件绑定(DOM2级模型);现代事件绑定在传统事件绑定基础上提供了更强大的功能;

    一 传统事件绑定的问题 

     1 // 脚本模型将一个函数赋值给一个事件处理函数;
     2     var box = document.getElementById('box');    // 获取元素;
     3     box.onclick = function(){                    // 元素点击触发事件;
     4         alert('Lee');
     5     }
     6 
     7 // 问题一:一个事件处理函数触发两次事件;
     8     window.onload = function(){                  // 第一组程序;
     9         alert('Lee');
    10     }
    11     window.onload = function(){                  // 第二组程序;
    12         alert('Mr.Lee');
    13     }
    14     // PS:当两组程序同时执行的时候,后面一个会把前面一个完全覆盖;
    15     // 导致前面的window.onload完全失效了;
    16 // 解决方案:
    17     window.onload = function(){                  // 第一组事件处理程序,会被覆盖;
    18         alert('Lee');
    19     }
    20     if(typeof window.onload == 'function'){      // 判断之前是否有window.onload;
    21         var saved = null;                        // 创建一个保存器;
    22         saved = window.onload;                   // 把之前的window.onload保存起来;
    23     }
    24     window.onload = function(){                  // 下一个要执行的事件;
    25         // saved()=window.onload = function
    26         if(saved)saved();                        // 判断之前是否有事件,如果有则先执行之前保存的事件;
    27         alert('Mr.Lee');                         // 执行本事件的代码;
    28     }
    // 问题二:事件切换器
        box.onclick = boBlue;                         // 第一次执行toBlue();
        function toRed(){
            this.className = 'red';
            this.onclick = toBlue;                    // 第三次执行roBlue(),然后来回切换;
        }
        function toBlue(){
            this.className = 'blue';
            this.onclick = toRed;                    // 第二次执行toRed();
        }
        // 这个切换器在扩展的时候,会出现一些问题:
        1.如果增加一个执行函数,那么会被覆盖;
        box.onclick = toAlert;                       // 被增加的函数;
        box.onclick = toBlue;                        // toAlert被覆盖了;
    
        2.如果解决覆盖问题,就必须包含同时执行;
        box.onclick = function(){                    // 包含进去,但可读性降低;
            toAlert();                               // 第一次不会被覆盖,但第二次又被覆盖;
            toBlue.call(this);                       // 还必须把this传递到切换器里;
        }
     1 // 综上三个问题:覆盖问题/可读性问题/this传递为题;
     2 // 我们创建一个自定义事件处理函数;
     3     function addEvent(obj,type,fn){             // 取代传统事件处理函数;
     4         var saved = null;                       // 保存每次触发的事件处理函数;
     5         if(typeof obj['on'+type] == 'function'){// 判断是不是存在事件;
     6             saved = obj['on'+type];             // 如果有,保存起来;
     7         }
     8         obj['on'+type] = function(){            // 然后执行;
     9             if(saved)saved();                   // 执行上一个;
    10             fn.call(this);                      // 执行函数,把this传递进去;
    11         }
    12     }
    13     addEvent(window,'load',function(){
    14         alert('Lee');                           // 可以执行;
    15     });
    16     addEvent(window.'load',function(){
    17         alert('Mr.Lee');                        // 可以执行;
    18     })
    19 
    20 // 用自定义事件函数注册到切换器上查看效果:
    21     addEvent(window,'load',function(){
    22         var box = document.getElementById('box');
    23         addEvent(box,'click',toBlue);
    24     });
    25     function toRed(){
    26         this.className = 'red';
    27         addEvent(this,'click',toBlue);
    28     }
    29     function toBlue(){
    30         this.className = 'blue';
    31         addEvent(this,'click',toRed);
    32     

    二 W3C事件处理函数

    // "DOM2级事件"定义了两个方法,用于添加事件删除事件的处理程序:addEventListener()和removeEventListener();

     1 // 所有DOM节点中都包含这两个方法,并且它们都接收3个参数:事件名/函数/冒泡或捕获的布尔值(true表示捕获,false表示冒泡);
     2     window.addEventListener('load',function(){
     3         alert('Lee');
     4     },false);
     5     window.addEventListener('load',function(){
     6         alert('Mr.Lee');
     7     },false);
     8     // PS:W3C的事件绑定好处:1.不需要自定义了;2.可以屏蔽相同的函数;3.可以设置冒泡和捕获;
     9     window.addEventListener('load',init,false);        // 第一次执行了;
    10     window.addEventListener('load',init,false);        // 第二次被屏蔽了;
    11     function init(){
    12         alert('Lee');
    13     }
    14 
    15 // 事件切换器
    16     window.addEventListener('load',function(){
    17         var box = document.getElementById('box');
    18         box.addEventListener('click',function(){       // 不会被覆盖/误删;
    19             alert('Lee');
    20         },false);
    21         box.addEventListener('click',toBlue,false);    // 引入切换;
    22     },false);
    23 
    24     function toRed(){
    25         this.className = 'red';
    26         this.removeEventListener('click',toRed,false); // 移除事件处理函数;
    27         this.addEventListener('click',toBlue,false);   // 添加需要切换的事件处理函数; 
    28     }
    29 
    30     function toBlue(){
    31         this.className = 'blue';
    32         this.removeEventListener('click',toBlue,false);
    33         this.addEventListener('click',toRed,false);
    34     }
    35 
    36 // 设置冒泡和捕获阶段
    37     document.addEventListener('click',function(){
    38         alert('document');
    39     },true);                                        // 设置为捕获;
    40 
    41     document.addEventListener('click',function(){
    42         alert('Lee');
    43     },false);                                        // 设置为冒泡;

    三 IE事件处理函数

    // IE中实现了与DOM中类似的两个方法:attachEvent()和detachEvent();

    // 这两个方法接收相同的参数:事件名函数;

     1 // 在使用这两组函数的时候,区别:
     2 // 1.IE不支持捕获,只支持冒泡;
     3 // 2.IE添加事件不能屏蔽重复的函数;
     4 // 3.IE中的this指向的是window而不是DOM对象;
     5 // 4.在传统事件上,IE是无法接受到event对象的;但使用了attachEvent()却可以;
     6     window.attachEvent('onload',function(){
     7         var box = document.getElementById('box');
     8         box.attachEvent('onclick',toBlue);
     9     });
    10 
    11     function toRed(){
    12         var that = window.event.srcElement;
    13         that.className = 'red';
    14         that.detachEvent('onclick',toRed);
    15         that.attachEvent('onclick',toBlue);
    16     }
    17 
    18     function toBlue(){
    19         var that = window.event.srcElement;
    20         that.className = 'blue';
    21         that.detachEvent('onclick',toBlue);
    22         that.attachEvent('onclick',toRed);
    23     }
    24     // PS:IE不支持捕获;
    25     // IE不能屏蔽;
    26     // IE不能传递this,可以call过去;
    27 
    28 // 在传统绑定上,IE是无法像W3C那样通过传参接受event对象;但如果使用了attachEvent()却可以;
    29     box.onclick = function(evt){
    30         alert(evt);                                // undefined;
    31     }
    32 
    33     box.attachEvent('onclick',function(evt){
    34         alert(evt);                                // object;
    35         alert(evt.type);                           // click;
    36     });
    37 
    38 // 兼容IE和W3C的事件切换器函数;
    39     function addEvent(obj,type,fn){                // 添加事件处理程序兼容;
    40         if(obj.addEventListener){
    41             obj.addEventListener(type,fn);
    42         }else if(obj.attachEvent){
    43             obj.attachEvent('on'+type,fn);
    44         }
    45     }
    46 
    47     function removeEvent(obj,type,fn){            // 移除事件处理程序兼容;
    48         if(obj.removeEventListener){
    49             obj.removeEventListener(type,fn);
    50         }esle if(obj.detachEvent){
    51             obj.detachEvent('on'+type,fn);
    52         }
    53     }
    54 
    55     function getTarget(evt){                     // 得到事件目标;
    56         if(evt.target){
    57             return evt.target;
    58         }else if(window.event.srcEleemnt){
    59             return window.event.srcElement;
    60         }
    61     }

    四 事件对象补充

     1 1.relatedTarget
     2 // 这个属性可以在mouseover和mouseout事件中获取从哪里移入从哪里移出的DOM对象;
     3     box.onmouseover = function(evt){            // 鼠标移入box;
     4         alert(evt.relatedTarget);               // 获取移入box之前的那个元素;
     5     }
     6     box.onmouseout = function(evt){             // 鼠标移出box;
     7         alert(evt.relatedTarget);               // 获取移出box之后到的那个元素;
     8     }
     9 
    10 // IE提供了两组与之对应的属性:fromElement和toElement;
    11 // 兼容函数
    12     function getEarget(evt){
    13         var e = evt || window.event;            // 得到事件对象;
    14         if(e.srcElement){                       // 如果支持srcElement,表示IE;
    15             if(e.type == 'mouseover'){          // 如果是over事件;
    16                 return e.fromeElement;          // 就使用from;
    17             }else if(e.type == 'mouseout'){     // 如果是out;
    18                 return e.toElement;             // 就使用to;
    19             }
    20         }else if(e.relatedTarget){              // 如果支持relatedTarget,表示W3C;
    21             return e.relatedTarget;
    22         }
    23     }
     1 2.阻止事件的默认行为
     2 // 一个超链接的默认行为就点击然后跳转到指定的页面;
     3 // 那么阻止默认行为就可以屏蔽跳转的这种操作,而实现自定义操作;
     4 // 取消事件默认行为还有一种不规范的做法,就是返回false;
     5     link.onclick = function(){
     6         alert('Lee');                        
     7         return false;                            // 直接返回false,就不会跳转了;
     8     }
     9     // PS:虽然return false;可以实现这个功能,但有漏洞;
    10     // 第一:代码必须写到最后,这样导致中间的代码执行后,有可能执行不到return false;
    11     // 第二:return false写到最前那么之后的自定义操作就失败了;
    12     // 解决方案:在最前面就阻止默认行为,并且后面还能执行代码;
    13     function preDef(evt){                        // 跨浏览器兼容阻止默认行为;
    14         var e = evt || window.event;
    15         if(e.preventDefault){
    16             e.preventDefault();                  // W3C,阻止默认行为;
    17         }else{
    18             e.returnValue = false;               // IE,阻止默认行为;
    19         }
    20     }
     1 3.上下文菜单事件contextmenu
     2 // 当我们右击网页的时候,会自动出现windows自带的菜单;
     3 // 那么我们可以使用contextmenu事件来修改我们指定的菜单;但前提是把右击的默认行为取消;
     4     addEvent(window,'load',function(){
     5         var text = docuemnt.getElementById('text');
     6         addEvent(text,'contextmenu',function(evt){        // 添加右键菜单事件处理程序;
     7             var e = evt || window.event;
     8             preDef(e);                                    // 阻止默认行为函数;
     9             var menu = document.getElementById('menu');   // 找到自定义的menu对象;
    10             menu.style.left = e.clientX+'px';             // 确定自定义menu在屏幕上的位置;
    11             menu.style.top = e.clientX+'px';
    12             menu.style.visibility = 'visible';            // 设置自定义menu的属性为可见;
    13             addEvent(document,'click',function(){         // 给document添加单击事件处理程序;
    14                 docuemnt.getElementById('myMenu').style.visibility = 'hidden';    //将自定义的menu隐藏;
    15             });
    16         });
    17     });
    1 4.卸载前事件beforeunload
    2 // 这个事件可以帮助在离开本页的时候给出相应的提示;"离开"或"返回"操作;
    3     addEvent(window.'beforeunload',function(evt){
    4         var evt = event || window.event;
    5         var message = '是否离开此页?';
    6         evt.returnValue = message;
    7         return message;
    8     });
     1 5.鼠标滚轮(mousewheel)和DOMMouseScroll
     2 // 用于获取鼠标上下滚轮的距离;
     3     addEvent(docuemnt,'mousewheel',function(evt){        // 非Firefox;
     4         alert(getWD(evt));
     5     });
     6     addEvent(docuemnt,'DOMMouseScroll',function(evt){    // Firefox;
     7         alert(getWD(evt));
     8     });
     9  
    10     function getWD(evt){
    11         var e = evt || window.event;
    12         if(e.wheelDelta){                                // mousewheel事件的滚动值保存在wheelDelta里;
    13             return e.wheelDelta;
    14         }else if(e.detail){                              // DOMMouseScroll事件的滚动值保存在detail里;
    15             return -evt.detail*30;                       // 保持计算的统一;
    16         }
    17     }    
  • 相关阅读:
    学习方法
    仿知乎Android端回答UI
    【LeetCode】:二叉树的Max,Min深度
    LeetCode:二叉树的前、中、后序遍历
    Caffe学习系列(四)之--训练自己的模型
    后端开发--之文件上传
    Python——轻量级web服务器flask的学习
    Django 部署(Apache下)
    Caffe学习系列(三)Docker安装及一些问题的记录
    Caffe学习系列(二)Caffe代码结构梳理,及相关知识点归纳
  • 原文地址:https://www.cnblogs.com/yizihan/p/4398236.html
Copyright © 2020-2023  润新知