zoukankan      html  css  js  c++  java
  • 前端笔记之JavaScript(十)深入JavaScript节点&DOM&事件

    DOM

    JavaScript语言核心。变量的定义、变量的类型、运算符、表达式、函数、if语句、for循环、算法等等。这些东西都属于语言核心,下次继续学习语言核心就是面向对象了。JavaScript能做非常多的事情:DOM开发、Ajax开发、Canvas开发、NodeJS开发、前端框架(ReactVueAngular等等)、HTML5开发。这些都需要语言核心的知识。

    DOM开发说白了就是浏览器中的页面效果开发,在2011年之前,DOM开发占据了前端开发工程师的90%的工作;但是现在,DOM开发的工作比重已经降到了10%以下。换句话说,2011年之前,前端 = 做特效的;2011年之后,前端要负责得到后台的数据接口,用前端MVC逻辑分层开发前端组建、界面、功能,还要写HTML5,还要做canvas动画!

    上层的框架屏蔽了下层的语言的一些麻烦、不方便的东西,并且提供更方便的API。

    jQuery就是干这个事情的,把JS中的不方便封装起来,暴露的API都是非常简便的。

    jQuery的哲学就是DOM编程领域的霸主,操作DOM节点、绑定监听、运动、css样式、Ajax等等都有封装。

    工作上都是用jQuery,如果不用jQuery也是用类似的东西。没有人会不用轮子去开发页面效果。

    JavaScript中Library表示“库”,如果这个库的功能很强大,甚至颠覆了传统编程的语法、行文习惯,我们就可以叫做“框架”。


    1.1 DOM是什么

    文档对象模型 (DOMDocument Object Model) HTML XML 文档的编程接口。它给文档(结构树)提供了一个结构化的表述并且定义了一种方式—程序可以对结构树进行访问,以改变文档的结构,样式和内容。 DOM 提供了一种表述形式— 将文档作为一个结构化的节点组以及包含属性和方法的对象。从本质上说,它将 web 页面和脚本或编程语言连接起来了

    到底什么是DOM就是你可以像操作对象一样操作HTML页面,而不是操作字符串。

    DOMweb 页面和脚本或编程语言连接起来了。

    回看一下我们之前学习的DOM操作,都在干嘛?我们在开发特效,但是微观的看,实际上在进行:

    1) 得到HTML节点

    2) 改变节点的属性

    3) 改变节点的样式

    4) 修改节点、删除节点、增加节点

    5) 节点之间的关系


    1.2原生JavaScript得到节点

     document.getElementById('box');

     document.getElementsByTagName('p');

    以上两是全线浏览器都兼容的得到元素方法。

    以下这些得到元素的方法都不兼容IE678 

    document.getElementsByName('aaa')[0]  //通过name属性得到元素们
    document.getElementsByClassName('pp') //通过类名得到元素们
    document.querySelector('#box');
    document.querySelectorAll('#box p');  //通过选择器得到元素们

    jQueryDOM开发的王者!帮我们解决了元素选择的兼容问题。

    jQuery底层很强大,比如$('.par1')机制不是getElementsByClassName(),而是在遍历所有节点,选择类名有par1的项。


    二、原生JavaScript节点关系

    jQuery中学习parent()children() siblings()next()prev()等等节点关系,JS中也有对应的属性。

    原生JS提供的节点关系很少:

    childNodesfirstChildlastChildparentNodenextSiblingpreviousSibling

     

    常见的nodeType值:

     1-普通元素节点、比如divp等等

     2-属性节点

     3-文本节点

     8-注释节点

     9-document节点

     10-文档DTD

     

    想要查看某一个元素的节点类型,直接读取它的nodeType属性即可。

    改变nodeType3的文本节点的内容,要改变他的nodeValue属性

     

    2.1 childNodes儿子节点

    childNodesIE678和高级浏览器不一致,高级浏览器认为所有的换行为空文本节点,而IE678无视这个空文本节点。

    div中没有文本节点,此时应该是4个节点,但是IE9Chrome、火狐会认为有9个节点、IE8认为有4个节点。

    高级浏览器会把空文本当做一个节点,标签前后的空文本也被算作一个。

    注释的前后算不算空文本节点,各个浏览器有不同的解释。所以用节点的时候,一定要去过滤、判断节点的nodeType是不是1

    <div id="box">
        <p></p>
        <p></p>
        <p></p>
        <p></p>
    </div>

     oBox.childNodes.length;  //Chrome数值9IE6784

    为解决兼容性问题(到底空文本算不算儿子,所以要封装函数来解决):

    可以利用nodeType是不是1来过滤文本节点、注释节点等,编写一个函数,得到一个标签真正的子节点。

    jQuery也有这层过滤:

    //封装一个children函数,这个函数能返回obj对象的所有真正儿子节点
    function chidlren(obj,num){
        var arr = []; //存储所有儿子
        //遍历所有的节点
        for(var i = 0; i < obj.childNodes.length;i++){
            //遍历的过程,寻找真正的HTML儿子节点、过滤文本、注释等节点
            //判断节点类型是不是1
            if(obj.childNodes[i].nodeType == 1){
                arr.push(obj.childNodes[i]); //如果是儿子节点就插入数组中
            }
        }
        //return arr;
        //返回的是:如果用户传入了num,返回某一个儿子,如果没有num,返回所有儿子
        return num ? arr[num] : arr;
    }
    chidlren(oBox)[2].style.backgroundColor = 'red';
    chidlren(oBox,3).style.backgroundColor = 'red';

    2.2 parentNode父亲节点

    parentNode属性表示父亲节点。任何节点的parentNodenodeType一定是1,也就是说父亲节点一定是标签节点。文本节点、注释节点没有儿子。

    var input = document.getElementsByTagName('input');
    for(var i = 0;i < input.length;i++){
       //当点击某个input时,如果自己被选中,此时改变父亲的颜色为绿色,否则为白色
       input[i].onclick = function(){
           if(this.checked){
               this.parentNode.style.backgroundColor = 'green';
           }else{
               this.parentNode.style.backgroundColor = 'white';
           }
       }
    }

    2.3 previousSiblingnextSibling兄弟节点

    上一个兄弟previousSibling、下一个兄弟nextSibling。同样的,文本节点也属于节点,注释也是节点,所以一个节点的上一个兄弟可能是文本、注释节点。原生JS中没有提供类似nextAll()prevAll()siblings()方法,如果节点没有上一个兄弟或下一个兄弟、返回null

     

     console.log(pp.previousSibling.nodeType)  

     console.log(pp.nextSibling.nodeType)

    var pp = document.getElementById("pp");
    //返回obj的前面一个兄弟
    function prevSibling(obj){
        //开始遍历obj节点的前面,直到遇见一个nodeType为1的节点
        var prev = obj;
        //循环遍历。注意while的条件是一个赋值语句!赋值语句也有表达式的
        while(prev = prev.previousSibling){
            if(prev.nodeType == 1){
                return prev;
            }
        }
        return null;
    }
    //得到真正的后面兄弟
    function nextSibling(obj){
        //开始遍历obj节点的前面,直到遇见一个nodeType为1的节点
        var next = obj;
        while(next = next.nextSibling){
            if(next.nodeType == 1){
                return next;
            }
        }
        return null;
    }
    //返回obj的前面所有兄弟
    function prevAll(obj){
        //开始遍历obj节点的前面,直到遇见一个nodeType为1的节点
        var prev = obj;
        var arr = [];
        while(prev = prev.previousSibling){
            if(prev.nodeType == 1){
                arr.push(prev);
            }
        }
        return arr;
    }
    prevSibling(pp).style.background = "red";
    nextSibling(pp).style.background = "green";
    prevAll(pp)[1].style.background = "green";

    三、原生JavaScript DOM节点操作

    HTML节点我们原来最多就是改改HTML属性,比如改改src属性;或者改改css样式,比如.style或者.css()

    现在的问题是,我们要增加节点、删除节点、移动节点、替换节点。

     


    3.1 createElement()创建和appendChild()添加

    创建节点的方法: create创建,Element元素。接收一个参数,就是创建的标签是什么。

     document.createElement()

    追加节点的方法:创建出来的节点不在DOM树上,所以就应该用appendChild()来添加到DOM树上:

     父亲.appendChild(新儿子);

    var btn = document.getElementById('btn');
    var txt = document.getElementById('txt');
    var ul = document.getElementsByTagName('ul')[0];
    btn.onclick = function(){
       //创建一个li标签,用变量oLi 来表示,创建除了的节点不是任何节点的儿子(没有在DOM树上)
       var oLi = document.createElement('li');
       oLi.innerHTML = txt.value; //改变这个节点的内容
       //把新创建的节点,追加到DOM树上
       ul.appendChild(oLi);
    }

    appendChild()一般来说就是用来追加新创建的节点,如果试图把页面上已经有的节点,appendChild()到别的地方,那么这个节点将移动,也就是说,同一个节点不可能在页面上两个地方出现。

    比如:

    <div id="box1">
        <p id="xiaoming">我是小明</p>
    </div>
    <div id="box2">
    
    </div>
    <script type="text/javascript">
         var box2 = document.getElementById('box2');
         var xiaoming = document.getElementById('xiaoming');
         box2.appendChild(xiaoming);
    </script>

    以上将把xioaming移动到box2里面。

    innerHTML创建节点:

    事实上,工作的时候很少用createElement。因为innerHTML足够好用,innerHTML也可以用来创建节点,甚至效率createElement还高。

    var year = document.getElementById('year');
    for(var i = 1950; i <= 2018;i++){
       //创建节点
       var op = document.createElement('option');
       //改变创建出来的节点内容
       op.innerHTML = i;
       //上DOM树
       year.appendChild(op); // 父亲.appendChild(新儿子);
    }

    innerHTML创建:

    for(var i = 1950; i <= 2018; i++) {
        year.innerHTML += '<option>'+i+'</option>';
    }

    JavaScript是动态变量:

    var oBox = document.getElementById('box');
    //得到box里面所有的p,现在box没有p,所以ops是一个空数组
    var ops = oBox.getElementsByTagName('p');
    var np = document.createElement('p'); //创建节点
    oBox.appendChild(np); //追加节点
    var np = document.createElement('p'); //创建节点
    oBox.appendChild(np); //追加节点
    var np = document.createElement('p'); //创建节点
    oBox.appendChild(np); //追加节点
    var np = document.createElement('p'); //创建节点
    oBox.appendChild(np); //追加节点
    var np = document.createElement('p'); //创建节点
    oBox.appendChild(np); //追加节点
    //这里弹出多少?初学者认为弹出0,因为先得到数组p,然后创建节点,节点又没有往数组里面push,所以应该ops数不变才对。
    //但是JS中存储DOM节点的变量是动态,不是一个瞬时照片,而是一个有生命的动态对象,当oBox里面的p标签变化时,ps也变化
    console.log(ops.length)

    3.2 insertBefore()添加

    appendChild是把新节点插入在父亲的所有子节点的后面,也就是说添加的节点就是父亲的最后一个儿子。

    我们可以在任意一个位置添加子节点:会在原有标杆儿子之前插入

     父亲.insertBefore(新儿子,原有标杆儿子)

    var btn = document.getElementById('btn');
    var txt = document.getElementById('txt');
    var ul = document.getElementsByTagName('ul')[0];
    var lis = document.getElementsByTagName('li');
    btn.onclick = function(){
       //创建一个li标签,用变量oLi 来表示,创建除了的节点不是任何节点的儿子(没有在DOM树上)
       var oLi = document.createElement('li');
       oLi.innerHTML = txt.value; //改变这个节点的内容
       //把新创建的节点,追加到DOM树上
       //在lis[0]的前面插入
       ul.insertBefore(oLi,lis[0]);
    }

    如果想每次都在开头添加,那么就是:

     ul.insertBefore(oLi,lis[0]);

    lis这个变量是动态的,这次添加的li,下回就是lis[0]


    3.3 removeChild()删除

    父亲.removeChild(儿子);
    <ul>
        <li>吃饭 <a href="###">删除</a></li>
        <li>睡觉 <a href="###">删除</a></li>
        <li>打豆豆 <a href="###">删除</a></li>
    </ul>
    <script type="text/javascript">
         var ul = document.getElementsByTagName('ul')[0];
         var lis = document.getElementsByTagName('li');
         var as = document.getElementsByTagName('a');
    
         for(var i = 0;i< as.length;i++){
            as[i].onclick = function(){
                ul.removeChild(this.parentNode);
    
                //如果要自杀,也要找到爸爸
                //this.parentNode.removeChild(this);
            }
         }
    </script>

    如果要自杀,也要找到爸爸:

     this.parentNode.removeChild(this);


    3.4 replaceChild()替换

    替换节点:

     父亲.replaceChild(新儿子,旧儿子)

    <div>
        <p>赵丽颖</p>
        <p id="xh">小黑</p>
        <p>迪丽热巴</p>
    </div>
    <script type="text/javascript">
         var oBox = document.getElementsByTagName('div')[0]
         var xh = document.getElementById('xh');
    
         //创建节点,孤儿节点
         var op = document.createElement('p');
         op.innerHTML = '朱老师'; //更改op的内容
         oBox.replaceChild(op,xh);
    </script>

    3.5 clone()克隆

    克隆节点,参数true表示深度克隆,节点里面的所有内容和事件一同复制。

    复制之后的节点是个孤儿节点,所以也要使用appendChild()等方法来添加上DOM树。

     克隆对象.cloneNode(true)

    <div id="box1">
        <ul>
            <li><span>赵丽颖</span></li>
            <li><span>迪丽热巴</span></li>
            <li><span>柳岩</span></li>
            <li><span>志玲姐姐</span></li>
        </ul>
    </div>
    <div id="box2">
    
    </div>
    <script type="text/javascript">
         var box1 = document.getElementById('box1');
         var box2 = document.getElementById('box2');
         var ul = document.getElementsByTagName('ul')[0];
         var lis  = document.getElementsByTagName('li');
    
         //克隆li和li的所有后代(要加true),然后追加到ul中
         //ul.appendChild(lis[0].cloneNode());  //克隆第0个li
         box2.appendChild(ul.cloneNode(true)); //克隆ul追加到box2中
    </script>

    四、事件监听

    一堆理论知识正要来袭。

    4.1事件流

    我们考虑一个结构,三个div嵌套,点击最内层的div,我们点击了谁?仅仅点击了最内层div吗?不是就像手指放在到一个同心圆中,实际上手指触碰到了任何一个圆。

    点击最内层的div,实际上浏览器会认为我们点击了所有的盒子,甚至于bodydocumentwindow

     

    为了描述事件的传播,人为规定了一个事件的传播方向,称为“事件流”。两个阶段:事件捕获阶段,事件冒泡阶段。

    “事件流”描述的是页面上各个元素接收事件的顺序。

     


    4.2 DOM0级事件监听

    DOM分级别,DOM0级、1级、2级、3级,是不同的标准,标准一直在升级。

    之前学习的on开头的语法添加事件,称为“DOM0级事件”。

    事件的触发一定是按照事件流的顺序,由于DOM0级只能监听冒泡阶段,所以顺序是:box3box2box1bodydocumentwindow 如果改变监听顺序,弹出顺序不变。

    box1.onclick = function(){ alert('我是box1');}
    box2.onclick = function(){ alert('我是box2');}
    box3.onclick = function(){ alert('我是box3');}
    document.body.onclick = function(){alert('我是body')}
    document.onclick = function(){alert('我是document')}
    window.onclick = function(){alert('我是window')}

    这种监听写法,就是DOM0级,就是把onclick当做属性添加给了div元素。

    这种事件添加方法,只能监听冒泡过程,不能监听事件捕获阶段。

     

    DOM0级事件处理函数中,this指的是触发事件的DOM元素,就是事件传播到的这个元素。

    DOM0级事件处理函数中,如果同一个对象,同一个事件名,绑定多个监听,后面写的覆盖前面写的。

     box1.onclick = function(){ alert('我是box1');}

     box1.onclick = function(){ alert('我是box1,后面写的');}

    DOM0级事件,IE67事件只能冒泡到documentIE8只能冒泡body,不能继续冒泡到window。也就是说不能给window对象添加事件。


    4.3 DOM2级事件监听

    DOM1级规范中,没有对事件进行改动,所以没有DOM1级的事情

    DOM2级做了新的规范,不用on**来绑定监听了,而是用一个方法

    W3C推出了addEventListener()函数,add添加、event事件,listener监听

    它接收三个参数:事件,函数,是否监听捕获阶段

     元素.addEventListener(事件,事件处理函数,是否添加到捕获阶段)

    第一个参数:事件名不用谢on。(clickmouseover

    第二个参数:函数可以是匿名函数,也可以是有名函数

    第三个参数:布尔值,true表示监听捕获,false表示监听冒泡阶段

    box1.addEventListener('click',function(){
       alert('我是box1的捕获阶段')
    },true);

    第三个参数是true,表示监听box1的捕获阶段的单击事件。

    要记住true表示捕获,false冒泡阶段:口诀:true上,false下。

    box1.addEventListener('click',function(){
       alert('我是box1的捕获阶段')
    },true);
    box2.addEventListener('click',function(){
       alert('我是box2的捕获阶段')
    },true);
    box3.addEventListener('click',function(){
       alert('我是box3的捕获阶段')
    },true);
    box1.addEventListener('click',function(){
       alert('我是box1的冒泡阶段')
    },false);
    box2.addEventListener('click',function(){
       alert('我是box2的冒泡阶段')
    },false);
    box3.addEventListener('click',function(){
       alert('我是box3的冒泡阶段')
    },false);

    box1的捕获→box2的捕获→box3的捕获→box3的冒泡→box2的冒泡→box1的冒泡

    坑:最内层的box3,谁先写就谁先执行,也就是说对于最内层的box3,就不区分冒泡和捕获了,对于不少罪内层的元素来说,改变事件监听的顺序,不会影响执行结果,先捕获,后冒泡。

     

    DOM2级事件中,如果给同一个元素,同一个事件名,同一个阶段添加多个事件监听,彼此不会覆盖,先写的先执行。

    box1.addEventListener('click',function(){
       alert('我是box1的冒泡阶段A')
    },false);
    box1.addEventListener('click',function(){
       alert('我是box1的冒泡阶段B')
    },false);
    box1.addEventListener('click',function(){
       alert('我是box1的冒泡阶段C')
    },false);

    弹出顺序是:ABC

    DOM2级事件监听中,this指的是触发事件的这个元素,就是事件传播到的这个元素。


    DOM2级小测试-看看执行顺序:正确答案在下篇文章。

    小题目:页面box1最大,嵌套box2box3,点击box3弹出顺序

    box2.onclick = function(){
       alert('A');
    }
    box2.onclick = function(){
       alert('B');
    }
    box2.addEventListener('click',function(){
       alert('C')
    },false);
    box2.addEventListener('click',function(){
       alert('D')
    },false);
    box2.addEventListener('click',function(){
       alert('E')
    },true);
    box2.addEventListener('click',function(){
       alert('F')
    },true);
    box3.addEventListener('click',function(){
       alert('G')
    },false);
    box3.onclick = function(){
       alert('H')
    }
    box3.addEventListener('click',function(){
       alert('I')
    },true);

    4.4低版本IE事件监听

    IE678不支持addEventListener()方法,支持attachEvent()

    box1.attachEvent('onclick', function(){
       alert(1)
    });

    第一个参数:必须写on,和addEventListener不一样

    第二个参数:事件处理函数

    没有第三个参数,不能自由选择添加到什么阶段,永远是冒泡阶段,也就是说IE678不能监听捕获阶段。

    box1.attachEvent('onclick', function(){
       alert('我是1a');
    });
    box1.attachEvent('onclick', function(){
       alert('我是1c');
    });
    box1.attachEvent('onclick', function(){
       alert('我是1b');
    });
    box2.attachEvent('onclick', function(){
       alert('我是2');
    });
    box3.attachEvent('onclick', function(){
       alert('我是3');
    });

    比较搞笑,如果给同一个元素添加多个事件名相同的监听,不互相覆盖,但是倒着执行,先执行后写:

    box1.attachEvent('onclick', function(){
       alert('我是a');
    });
    box1.attachEvent('onclick', function(){
       alert('我是b');
    });
    box1.attachEvent('onclick', function(){
       alert('我是c');
    });

    弹出cba

    最诡异是,this永远是window对象而不是事件传播到的元素。

    box1.attachEvent('onclick', function(){
       alert(this === window);
    });

    所以最正确的工作实践,就是用DOM0级事件监听方法,除非基于特别充分的理由,否则不用DOM2级。什么时候理由充分用DOM2级呢?比如一些新兴事件,如手机事件:touchstarttouchmovetouchend事件等等。只能用DOM2级。

    上面学习的就是一些理论知识,总结一下:

    事件流永远是先下(捕获)后(冒泡),但是不同监听方式,决定了监听那一部分。

    面试意义大于实际意义!

    jQuery中用的就是DOM2级,也有轮子,jQuery事件同名不会被覆盖。


    4.5事件监听移除

    DOM0级事件监听的移除很简单,直接把事件属性赋值给null即可。

    var box1 = document.getElementById('box1');
    box1.onclick = function(){
       alert('你好,再次点击就没有效果了');
       box1.onclick = null; //移除事件监听
    }

    DOM2级事件监听移除,必须指名道姓移除,也就是说,如果是匿名函数添加的事件监听,是不可能去掉的。

    添加的时候要有名字:

    box1.addEventListener('click',function fun(){
       alert('你好');
       box1.removeEventListener('click',fun,true);
    },true);

    点击按钮后,移除box1的事件监听:

    btn.onclick = function(){
       box1.removeEventListener('click',fun,true);
    }

    IE678detachEvent即可,同样,也必须起名。

    box1.attachEvent('onclick',fun)
    function fun(){
       alert('你好');
    }
    btn.onclick = function(){
       box1.detachEvent('onclick',fun);
    }

    五、事件对象event

    这里的知识就不是理论了 ,有实战价值。

    5.1 event兼容性问题

    在任何事件中,都有事件对象event。浏览器会往事件处理函数中,传入一个实参,就是事件对象,里面封装了你这次触发事件(点击、鼠标移入、移出、键盘按下)的细节。比如鼠标位置、是否按下某个键等等。

    一般用变量event来接收,注意,不是必须的,名字可以改。

    所有事件的细节,都被封装到event对象里面。

    比如clinetXclinetY就是这次鼠标点击的位置。

    先说兼容性问题,IE678中,event这事件对象不是实参,而是全局变量,系统会在每一个事件发生的时候,都去改变这个全局变量的值:

    box.onclick = function(){  //圆括号不能写event,如果写了,就遮蔽了全局的event
       alert(event.clientX)
    }

    兼容写法:

    box.onclick = function(event){
       //因为在Chrome中event是实参,IE678events全局变量,所以用或的短路语法,它支持哪个用哪个
       var event = event || window.event;
       alert(event.clientX)
    }

    5.2事件对象属性

     event.type      返回事件类型,没有on,比如“click

     event.target    返回你点击的最小哪个元素,即使这个元素身上没有监听,也返回它

     event.currentTarget  返回自己,this一定和它是同一个元素,都是自己

     event.bubbles     返回布尔值,表示这个事件是否冒泡

    bubbles属性,表示事件是否冒泡

    box1.onmouseover = function(event){
       var event = event || window.event;
       console.log(event.bubbles); //表示是否冒泡
    }

    基本上所有事件这个属性都是true,表示这个事件冒泡,但是要记住:

     onmouseoverevent.bubbles是true,表示冒泡

     onmouseoutevent.bubbles是true,表示冒泡

     onmouseenterevent.bubbles是false,表示不冒泡

    有两个事件不冒泡:

     onmouseentermouseleaveevent.bubblesfalse,不冒泡

    onmouseentermouseleave这两个事件IE678910全面兼容!反而是Chrome30之前不兼容,但是现在可以当做全面兼容。它们两个事件是著名天生不冒泡的,当一个内部元素鼠标进入了,会执行这个元素的事件处理函数,但是事件捕获继续往外层传播。它的外层盒子不会触发onmouseenter事件。

    box1.onmouseenter = function(event){
        alert('鼠标进入了box1')
    }
    box2.onmouseenter = function(event){
        alert('鼠标进入了box2')
    }
    box1.onmouseout = function(event){
        alert('鼠标离开了box1')
    }
    box2.onmouseout = function(event){
        alert('鼠标离开了box2')
    }

    onmouseentermouseleaveonmouseoveronmouseout好用

    // $('#box').mouseenter(function(){
    //    $(this).children('.mask').slideDown();
    // });
    // $('#box').mouseleave(function(){
    //    $(this).children('.mask').slideUp();
    // });
    $('#box').mouseover(function(){
       $(this).children('.mask').slideDown();
    });
    $('#box').mouseout(function(){
       $(this).children('.mask').slideUp();
    });

    targetsrcElement属性,表示事件发生的最内层元素

    chrome同时支持下面2个属性,IE只支持srcElement

     var target = event.target || event.srcElement;

    用这个属性可以优化代码效率,可以制作“事件委托”把子元素的事件,委托给父亲,父亲通过event.target来判断是谁触发了事件。不使用事件委托,我们将会有很多事件监听;使用事件委托,事件监听只有1个。提升了页面的效率。

    box1.onclick = function(event){
       var event = event || window.event;
       var target = event.target || event.srcElement;
       alert(target.id)
    }

    事件委托:

    比如,小圆点添加监听,不要给所有li,直接给ol,让olevent.target这个元素有cur

    <body>
        <ol>
            <li class="cur">0</li>
            <li>1</li>
            <li>2</li>
            <li>3</li>
            <li>4</li>
            <li>5</li>
        </ol>
    </body>
    <script type="text/javascript" src="js/jquery-1.12.4.min.js"></script>
    <script type="text/javascript">
        $('ol').mouseover(function(event){
            var event = event || window.event;
            //得到触发事件的最小元素
            var target = event.target || event.srcElement;
            //让触发事件的元素添加cur
            $(target).addClass('cur').siblings().removeClass('cur');
        });
    </script>

    当页面上有大量的重复元素要添加监听的时候,比如100/200个,一定要注意事件委托。

    window.onload = function(){
      var oUl = document.getElementById("ul1");
      oUl.onclick = function(ev){
        var ev = ev || window.event;
        var target = ev.target || ev.srcElement;
        if(target.nodeName.toLowerCase() == 'li'){
                alert(123);
             alert(target.innerHTML);
        }
      }
    }

  • 相关阅读:
    基于redission的分布式锁
    kafka在Windows环境下启动
    Synchronized优化总结
    mysql死锁总结
    索引是建立得越多越好吗?
    show processlist 详解
    RocketMQ高可用机制同步刷盘、异步刷盘和同步复制、异步复制
    Redlock红锁总结
    C#2.0泛型
    《解剖PetShop》系列之四:PetShop之ASP.NET缓存 (转)
  • 原文地址:https://www.cnblogs.com/rope/p/10610253.html
Copyright © 2011-2022 走看看