zoukankan      html  css  js  c++  java
  • javaScript事件知识点

     提纲

    • event事件
    • event事件中常用属性
    • 元素注册事件
    • 事件冒泡
    • 事件委托
    • 事件监听和解绑的兼容封装
         
     
     
    事件event对象
     
    也就是说有事件的情况下,才存在事件对象;事件对象中存着该事件的相关信息;
     
    兼容处理
    document.onclick = function(event){
             event = event ||  window.event;
    }
     
    主流浏览器支持事件函数的参数event,而ie不支持参数的形式通过window.event获取。
     
     
    event事件中常用属性
     
    clientY     支持IE           获取的是鼠标到浏览器可视窗口顶部的距离
     
    clientX    支持IE           获取鼠标到浏览器可视窗口左边的距离
     
    pageY    不支持IE8及以下     获取鼠标到文档顶部的距离
     
    pageX    不支持IE8及以下     获取鼠标到文档左边的距离
     
    对于主流浏览器和IE9及以上都支持
     
     
    如果需要使用pageX和pageY就需要解决兼容问题,以便符合需求。
     
     
     
    clientX/clientY和 pageX/pageY 兼容处理代码
     
    function getXY(ev){
    var ev = ev || window.event;
    var x = 0,y = 0;
    if(ev.pageX){
    x = ev.pageX;
    y = ev.pageY;
    }else{
    // 滚动条的距离
    var cleft = document.body.scrollLeft || document.documentElement.scrollLeft;
    var ctop = document.body.scrollTop || document.documentElement.scrollTop;
    x = ev.clientX + cleft;
    y = ev.clientY + ctop;
    }
    return {x : x,y : y};
    }
     
     
     
     

     
    元素注册事件
     
    注册事件方式有两种,直接注册和监听注册事件两种方式。
     
     
    以点击事件为例:
    第一种直接注册
    document.onclick = function(){
        alert( 1 );
    }
     
    兼容性:兼容所有浏览器
     
     
    直接注册有两种写法,一种是直接使用匿名函数,一种是定义一个有名函数,进行赋值。
     
    var oEle = docuemnt.getElementById(' btn ');
     
    oEle.onclick = function(){ }
     
    或是
     
    oEle.onclick = btnFn;
     
    function  btnFn(){  } 
     
     使用名定义的函数。
     
     
     
    注意注册事件的函数,不能定义成函数表达式,如下:
     
    oEle.onclick = btnFn;
    var btnFn  =  function(){  };   
     
     
    弊端:直接注册事件,同一个元素添加多个事件容易被覆盖。通常的开发中是使用第二种形式。
     
     
    解除元素注册绑定的事件
     
    ele.eventName = null;
     
    例如解除元素oEle的click事件
     
    oEle.onclick = null; 
     
     
     
    第二种监听事件也是事件监听
     
    el.addEventListener('eventName', eventFn , boolean)只支持主流浏览器, 不支持IE
    el.attachEvent('eventName', eventFn , boolean) 不支持主流浏览器,支持IE
     
    eventName第一个参数事件名;
     
    eventFn第二个参数处理方法,也可以是匿名函数
     
    boolean值实质决定了该事件执行的顺序,所以与每个事件的事件对象没有必然的联系。
     
    boolean值是true,表示以事件捕获的顺序执行事件,也就是父元素向子元素执行,最后执行当前点击时元素所绑定的事件;
     
    boolean值是false,表示以事件冒泡的顺序执行事件,也就是先执行当前点击时元素所绑定的事件 
     
    // 主流浏览器
    document.addEventListener( 'click',function(){
           alert( 1 );
    },false);
     
    // IE浏览器
    document.attachEvent( 'onclick',function(){
        alert( 1 );
    },false);
     
    //兼容主流浏览器和IE浏览器普通写法
    document.addEventListener( 'click',function(){
           alert( 1 );
    },false);
     
    document.attachEvent&&document.attachEvent( 'onclick',function(){
        alert( 1 );
    },false);
     
    其实就是写两套代码,当然这种做法是非常愚蠢的。 前辈们已为我们想出了办,这也是设计模式中的适配器设计模式。
     
     
     
    元素绑定事件统一进行兼容
     
    //事件绑定
    function addEvent(el, type, callback) { //这样就没有办法传递参数了
    var fn = function (e) {
    var e = e || window.event;
    callback.call(el, e); //让回调中的this和此时的this都指向el, args是一个参数数组
    };
     
    if( window.addEventListener ){
    el.addEventListener(type , fn);
    }else {
    el.attachEvent('on'+ type , fn);
    }
     
        return fn; //返回fn是为了解绑的时候统一
    }
     
     
    addEventListener()和attchEvent()事件解绑分别是以下两个事件
     
    // 事件解绑
    function removeEvent( obj , eName , fn) {
    if ( document.addEventListener ){
        obj.removeEventListener(eName, fn);
    }else{
        obj.detachEvent('on'+eName , fn);
    }
     
    }
     
    注意,在事件绑定和解绑的时候,fn指的的是同一个方法,所以在绑定的时候需要返回
     
     
    这些知识点很简单,大家应该都知道,我也是回过头把初学时不完整的进行补充,更重要的是对其中关键点有了一步深刻的认识和理解。
     

     
    事件冒泡
     
    冒泡的概念,当子元素绑定事件的时候,事件会向上传递,直到根元素。
     
    为页面中id=box的div添加一个onclick事件,event对象里path属性,可以看到事件每一级的冒泡,如下
     
     
    阻止事件冒泡
     
    在实际应用中,我们是不希望事件向上传递,因此也有了阻止事件冒泡
     
    return false;     //即阻止了事件的默认行为,有阻止了事件冒泡; 只是在使用事件监听注册事件时是不管用的
     
     
    event.cancelBubble = true;  //阻止事件冒泡,只是不符合W3C规范
     
     
    event.stopPropagation();  //阻止事件冒泡,符合W3C规范
     
     
    event.preventDefault();  //阻止链接行为,没有阻止冒泡
     
     
    在为元素注册事件时,一般都要添加阻止事件冒泡,这样做似乎更合理一些。
     
     

     
    事件委托
     
    事实子元素要注册事件,确添加到其父元素上,称之为事件委托。
     
    例如:
     
    我现在有一组li列表,我想为每一个 li 添加一个点击事件
     
    实例实现点击li列表,输出li的索引值
     
    常见的实现方法
    var list = document.querySelectorAll('.ulBox li');
    for(var i=0 ,len=list.length; i < len; i++ ){
    list[i].index = i; //自定义属性,存储每个li的索引值
    list[i].onclick = function () {
    console.log(this.index); // 输出当前点击的索引值
    }
    }
     
     
    利用事件委托来实现
     
    oUl.onclick = function (ev) {
    var ev = window.event || ev;
    var tag = ev.target || ev.srcElement; //取到当前点击的元素
    var ali = tag.parentNode.children; //这是一个文档对象,需要转化为数组
    var arrALi =[].slice.call(ali); //把类数组对象转化为数组对象
    if(tag.nodeName.toLocaleLowerCase() === 'li'){
    console.log( arrALi.indexOf(tag) )
    }
    }
    var tag = ev.target || ev.srcElement;  
    这行代码ev.target是不兼容IE8的,所以有了ev.srcElement这个来处理IE8兼容问题滴。
     
     
     
    写每一行代码,都是有目的的;所写的每一行代码都是有原因的;这似乎就像存在的就是合理的,合理的就会存在一样哒~~
     

     
     
    事件监听和解绑的兼容封装
     
     注册事件的代码
     
    function addEvent(obj, eName, callback) {
    var fn = function (e) {
    e = window.event || e;
    e.stopPropagation();
    callback.call(obj,e);
    };
    /*
    obj.myEvent存放放注册事件的形式
    * obj.myEvent = {
    * ['click':fn1, 'click':fn2, 'mouse':fn1],
    * ['mouse',fn1]}
    *
    * */
    //obj是否存在自定义属性,当不存在时为每一个Dom对象添加一个自定义属性,存放该对象注册事件的执行函数
    if (!obj.myEvent)obj.myEvent = {};
     
    //obj的自定义属性中是否存在eName这个事件,存在继续向下执行,不存在则添加
    if(!obj.myEvent[eName])obj.myEvent[eName] = [];
     
    obj.myEvent[eName].push(fn);//把每次注册事件的执行函数,pushobj的自定义属性中
    window.addEventListener?obj.addEventListener(eName, fn):obj.attachEvent('on'+eName, fn);
    return fn; //返回这个函数,目的是为了解绑
    }
     
     
    解绑事件的代码
     
    function removeEvent(obj, eName, fnName) {
    if(obj.myEvent && obj.myEvent[eName]){ //obj元素是否有事件并注册了事件
    var eNameArr = obj.myEvent[eName]; //obj当前要解除的所有事件函数存放在一个数组里
    var len=eNameArr.length; //一个元素注册相同事件的个数
    if( fnName ){ //解除元素指定的事件函数
    var idx = -1;
    for(var i=0; i<len; i++){
    if(eNameArr[i] === fnName){
    idx = i;
    break; //跳出循环
    }
    }
     
    if(idx != -1){
    obj.myEvent[eName].splice(idx,1); //删除数组中指定位置的数组
    window.addEventListener?obj.removeEventListener(eName, fnName):obj.detachEvent('on'+eName, fnName);
    }
     
    }else { //解除元素所有的指定事件函数
    for(i=0; i<len; i++){ //循环移除元素的所有eName事件
    window.addEventListener?obj.removeEventListener(eName, eNameArr[i]):obj.detachEvent('on'+eName, eNameArr[i]);
    }
    obj.myEvent[eName] = []; //清空元素自定义属性中的eName说有事件
    }
    }
    }
  • 相关阅读:
    Centos7安装Zabbix4.0步骤
    linux异常处理:selinux配置错误导致无法重启
    自学Python5.4-类 _init_方法
    自学Python5.3-类和对象的简单操作
    自学Linux Shell9.3-基于Red Hat系统工具包:RPM属性依赖的解决方式-YUM在线升级
    自学Linux Shell9.4-基于Red Hat系统工具包存在两种方式之二:源码包
    自学Linux Shell9.2-基于Red Hat系统工具包存在两种方式之一:RPM包
    JS 对象API之修改、删除对象的属性
    JS 对象API之判断自有属性、共有属性
    JS 对象API之判断父对象是否在子对象的原型链上
  • 原文地址:https://www.cnblogs.com/wjh0916/p/9413807.html
Copyright © 2011-2022 走看看