美文网首页
JavaScript进阶教程-4.dom零级 二级事件基础和实战

JavaScript进阶教程-4.dom零级 二级事件基础和实战

作者: 超跑飞飞 | 来源:发表于2020-02-21 11:38 被阅读0次

    事件基础和事件委托

    事件委托

    事件的兼容性问题:
    1、事件对象本身的获得方式不同,IE是用全局的window.event,chrome是浏览器自动会给把事件对象传给事件触发的方法,作为此方法的第一个参数。
    1.1、chrome也是支持window.event的
    2、事件传播和阻止事件传播的方式:ie是e.cancelBubble=true;标准浏览器是用的e.stopPropagation()
    3、取消事件默认行为:IE是e.returnValue=false;标准浏览器用的是e.preventDefault();
    4、触发事件的事件源不一样:IE是e.srcElement,标准浏览器是e.target
    5、IE不支持e.pageX、e.pageY
    6、最大的兼容性问题在于对DOM2级事件的支持上
    什么DOM2级事件:就是在DOM的第二个版本中,实现的事件绑定方式
    DOM0 (本身没有DOM0这么个概念,它是相对于DOM1来讲的) DHTML(动态HTML)
    DOM是独立于JS之外的一个API,目的为了跨语言操作标记语言(主要是XML)应运而生的一种技术
    DOM Core(DOM1):解决的文档的层次结构和增删改查的一些方法属性
    DOM2 有一部分是实现更好的事件的解决方案
    DOM3

    
    document.body.form;
    document.forms;
    document.anchors;
    document.all;
    document.all["div1"]
    
    document.onclick;
    var ele=document.getElementById("div1");
    function fn1(){alert(1);}
    function fn2(){alert(2);}
    
    var n=0;
    //如果点击超过2次,则从事件移除些方法
    function fn3(){
        n++;
        if(n==2){
            
        }
        alert(3);}
    function fn4(){alert(4);}
    ele.onclick=fn1;
    ele.onclick=function(){fn1();fn2();fn3();fn4();}
    //DOM2级事件的方法
    EventTarget.prototype.addEventListener;
    EventTarget.prototype.removeEventListener;
    //DOM2级事件中新增加的事件类型
    document.addEventListener("DOMContentLoaded",fn2,false);
    
    //文档的中标签已经加载并解析(标签已经在网页上显示了)就触发些事件,至于外链的图片、样式、JS是否加载或运行,跟这个事件无关。
    $(document).ready(function(e) {
        //"DOMContentLoaded"
        fn1
    });
    //$的参数如果是一个function,则表示文档内容加载完成之后运行此方法,也就是$(document).ready()这个事件,其实就是"DOMContentLoaded"这个事件
    $(fn1);//这个表示内容加载完成之后,触发fn2这个方法,相当于下面
    $(document).ready(fn2);
    
    //以下
    $("#div1").click(fn1);
    $("#div1").click(fn2);
    ele.addEventListener("click",fn1,false);
    ele.addEventListener("click",fn2,false);
    //浏览器的所有资源都已完成加载(当然,会有加载失败的:超时),触发onload事件
    window.onload;
    
    for(var i=0;true;i++){
        console.log(i); 
    }
    
    document.addEventListener("DOMContentLoaded",function(){alert("ContentLoaded");},false)
    
    
    

    dom二级事件兼容问题

    
    var ele=document.getElementById("div1");
    function fn1(){alert(1);}
    function fn2(){alert(2);}
    
    var n=0;
    //如果点击超过2次,则从事件移这个方法
    function fn3(){
        n++;
        if(n==2){//第二次执行的时候执行移除,到第三次的时候生效
            this.removeEventListener("click",fn3,false);
        }
        alert(3);}
    function fn4(){alert(4);}
    ele.addEventListener("click",fn1,false);//第三个参数是指:是否在捕获阶段绑定此方法
    ele.addEventListener("click",fn2,false);
    ele.addEventListener("click",fn3,false);
    ele.addEventListener("click",fn4,false);
    
    
    <!doctype html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>无标题文档</title>
    <style type="text/css">
    #div1{ height:100px; background:red;}
    </style>
    </head>
    
    <body>
    <div id="div1">div1</div>
    </body>
    </html>
    <script>
    var ele=document.getElementById("div1");
    function fn1(){alert(1);}
    function fn2(){alert(2);}
    
    var n=0;
    //如果点击超过2次,则从事件移这个方法
    function fn3(){
        n++;
        if(n==2){//第二次执行的时候执行移除,到第三次的时候生效
            //this.removeEventListener("click",fn3,false);
            unbind(ele,"click",fn3);
            //不能把上一行代码中的ele换成this
        }
        alert(3);}
    function fn4(){alert(4);}
    function fn5(){alert(5);}
    function fn6(){alert(6);}
    function fn7(){alert(7);}
    function fn8(){alert(8);}
    function fn9(){alert(9);}
    function fn10(){alert(10);}
    function fn11(){alert(11);}
    function fn12(){alert(12);}
    bind(ele,"click",fn1);
    bind(ele,"click",fn2);
    bind(ele,"click",fn3);
    bind(ele,"click",fn4);
    bind(ele,"click",fn5);
    bind(ele,"click",fn6);
    bind(ele,"click",fn7);
    bind(ele,"click",fn8);
    bind(ele,"click",fn9);
    bind(ele,"click",fn10);
    bind(ele,"click",fn11);
    bind(ele,"click",fn12);
    function bind(ele,type,handler){//handler直译为句柄,方法名,方法引用的意思
        if(ele.addEventListener){
            ele.addEventListener(type,handler,false);   
        }else if(ele.attachEvent){
            ele.attachEvent("on"+type,handler);
        }
        
    }
    
        function unbind(ele,type,handler){
            if(ele.removeEventListener){
                ele.removeEventListener(type,handler,false);
            }else if(ele.detachEvent){
                ele.detachEvent("on"+type,handler);
            }
        }
    
    </script>
    
    
    <!doctype html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>无标题文档</title>
    <style type="text/css">
    #div1{ height:100px; background:red;}
    </style>
    </head>
    
    <body>
    <div id="div1">div1</div>
    </body>
    </html>
    <script>
    var ele=document.getElementById("div1");
    function fn1(){
        this.innerHTML="点过"+n;
        alert(1);}
    function fn2(){alert(2);}
    
    var n=0;
    //如果点击超过2次,则从事件移这个方法
    function fn3(){
        n++;
        if(n==2){//第二次执行的时候执行移除,到第三次的时候生效
            //this.removeEventListener("click",fn3,false);
            unbind(this,"click",fn3);//
            unbind(this,"click",fn2);
            //不能把上一行代码中的ele换成this
            //执行bind的时候,第一次fnTemp是fn1的变形
            //              第二次fnTemp是fn2的变形
            //              第三次fnTemp是fn3的变形
        }
        alert(3);}
    function fn4(){alert(4);}
    function fn5(){alert(5);}
    function fn6(){alert(6);}
    function fn7(){alert(7);}
    function fn8(){alert(8);}
    function fn9(){alert(9);}
    function fn10(){alert(10);}
    function fn11(){alert(11);}
    function fn12(){alert(12);}
    bind(ele,"click",fn1);
    bind(ele,"click",fn2);
    bind(ele,"click",fn3);
    /*bind(ele,"click",fn4);
    bind(ele,"click",fn5);
    bind(ele,"click",fn6);
    bind(ele,"click",fn7);
    bind(ele,"click",fn8);
    bind(ele,"click",fn9);
    bind(ele,"click",fn10);
    bind(ele,"click",fn11);
    bind(ele,"click",fn12);*/
    var fnTemp=null;
    function bind(ele,type,handler){//handler直译为句柄,方法名,方法引用的意思
        if(ele.addEventListener){
            ele.addEventListener(type,handler,false);   
        }else if(ele.attachEvent){
            
            //1、事件触发的时候handler方法执行
            //2、让handler方法里的this指向ele
            
            //记好一个原则:如果是解决this关键字的指向,则记好用call或apply方法
            
            //以下的处理方式已经就可以实现让事件触发的时候,handler里的this指向ele了。如果就是解决仅仅是解决this关键字关键,已经就解决了
            
            //即可以把fnTemp保存下来,还要保证fnTemp的安全,还要把多次变形得成的fnTemp都可以保存下来,并且在unbind里还可以识别出来当前这个fnTemp是由那个方法变形而来
            //ele.abindclick=[];//自定义属性
            //if(!ele.abindclick){
                /*ele[handler]
                ele[fn1]
                ele["fn1"]
                fn1=function(){};
                fn2=function(){};*/
            if(!ele["abind"+type]){
                //这个自定义属性的命名规则是:abind是属性的前缀,click是属性的区分符
                //ele.click
                //为什么要用click来命名呢?把绑定在不同事件类型上的方法,以事件类型做为命名的依据来定义不同的数组,来保存不同的事件上的方法。
                //但是我们又不能直接用事件类型作属性,容易和系统属性引起冲突,所以才在它前面加个前缀(为了让属性名变长,降低冲突的机率)
                //ele[type]=[];
                
                ele["abind"+type]=[];   
            }
            var fnTemp=function(){handler.call(ele);};
            fnTemp.photo=handler;//photo"照片",保存着它原来的面貌
            ele["abind"+type].push(fnTemp);
            ele.attachEvent("on"+type,fnTemp);
        }
        
    }
    
        function unbind(ele,type,handler){
            if(ele.removeEventListener){
                ele.removeEventListener(type,handler,false);
            }else if(ele.detachEvent){
                var a=ele["abind"+type];
                //a里的第i项可能就是handler变形而来
                //a[i]==handler
                //现在需要一个机制,能识别出a[i]是由handler变形来的
                if(a){
                    for(var i=0;i<a.length;i++){
                        if(a[i].photo==handler){
                            ele.detachEvent("on"+type,a[i]);
                            return; 
                        }
                    }
                }
                //ele.detachEvent("on"+type,fnTemp);
            }
        }
    
    </script>
    
    

    实战 面向对象的拖拽功能开发

    <!doctype html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>无标题文档</title>
    <style type="text/css">
    div{ width:100px; height:100px; position:absolute; background:green; top:100px; left:100px; cursor:move; -webkit-user-select:none;}
    </style>
    </head>
    
    <body>
    <div id="div1" style="left:0; top:0; background:red;"></div>
    <div id="div2"><img src="" height="100" width="100"></div>
    <div id="div3" style="top:200px; left:150px; background:blue;"></div>
    </body>
    </html>
    <script src="event1.js"></script>
    <script>
    //面向对象的编程强在管理、拓展功能。强项不是逻辑
    //在使用面向对象编程方式之前,先要确定设计原则:this关键字的问题。
        //this要指向当前类的实例,无论是构造函数还是原型函数,this都要指是指向类的实例。
        //这一点会和事件原则中this冲突,如果存在冲突,强制使this指向类的实例
    //一但使用的面向对象,代码的可读性会变差。
    //使用面向对象,要理解整个类的体系
    
    function Drag(ele){//构造函数是初始化的作用
        this.x=null;
        this.y=null;
        this.mx=null;
        this.my=null;
        this.ele=ele;//把被拖拽的元素保存到当前实例的ele属性上,以便其类上的其它函数能够访问。如果不把ele保存到this.ele上,其它方法无法访问这个私有变量ele。一个方法里定义的变量或形参,都是私有变量,其它的函数里无法访问;但如果我们把一个值保存到this的属性,则这个属性就成了公有变量
        /*
        function processThis(fn,obj){
            //返回的新方法:让fn的功能不变,但是this被强制改变了
            return function(e){fn.call(obj,e);this} 
            function fn1(){
                this;
                fn();   
            }
        }
        */
        this.DOWN=processThis(this.down,this);
        //processThis会返回一个新的方法,这个新的方法里还是执行老的方法this.down,但是会让this.down里的this一定指向当前类的实例
        this.MOVE=processThis(this.move,this);
        this.UP=processThis(this.up,this);
        
        on(ele,"mousedown",this.DOWN);
        //以下是错误的绑定方式
        //on(ele,"mousedown",this.down);//我们原则是:down方法无论在什么情况下里的this都指向类的实例this
        
        
        
        
    }
    
    Drag.prototype.down=function(e){
        this.x=this.ele.offsetLeft;
        this.y=this.ele.offsetTop;
        this.mx=e.pageX;
        this.my=e.pageY;
        
        if(this.ele.setCapture){
            this.ele.setCapture();
            on(this.ele,"mousemove",this.MOVE);
            on(this.ele,"mouseup",this.UP);
        }else{
            on(document,"mousemove",this.MOVE);
            on(document,"mouseup",this.UP);
        }
        e.preventDefault();
        //一定要注意的是:如果事件是用DOM2事件绑定方法来绑定的,那么阻止事件的默认行为一定要用e.preventDefault()这个方法
        
    }
    Drag.prototype.move=function(e){
        this.ele.style.left=this.x+e.pageX-this.mx+"px";
        this.ele.style.top=this.y+e.pageY-this.my+"px";
        
        
    }
    Drag.prototype.up=function(e){
        if(this.ele.releaseCapture){
            this.ele.releaseCapture();
            off(this.ele,"mousemove",this.MOVE);
            off(this.ele,"mouseup",this.UP);
        }else{
            off(document,"mousemove",this.MOVE);
            off(document,"mouseup",this.UP);
        }
    }
    
    var obj1=new Drag(div1);
    //操作的主体,上下文,是ele这个dom元素;现在操作的主体是obj1这个对象,这个obj1中,承载了所有的和拖拽相关的信息(属性和方法)
    new Drag(div2);
    new Drag(div3);
    
    
    
    
    </script>
    
    
    

    相关文章

      网友评论

          本文标题:JavaScript进阶教程-4.dom零级 二级事件基础和实战

          本文链接:https://www.haomeiwen.com/subject/urfcqhtx.html