【4858美高梅】dom二级事件基础知识,如何优雅的卷入三个DOM事件库

By admin in 4858美高梅 on 2019年5月5日

一、DOM0级事件和DOM二级事件

【4858美高梅】dom二级事件基础知识,如何优雅的卷入三个DOM事件库。DOM 0级事件是因素内的多个民用属性:div.onclick = function ()
{},对八个私家属性赋值(在该事件上绑定3个艺术)。由此可见DOM
0级事件只好给成分的某2个表现绑定二遍艺术,第一次绑定会把前边的遮盖掉。

DOM
二级事件是让DOM成分通过原型链平昔找到伊夫ntTarget那几个内置类原型上的add伊芙ntListener方法来贯彻的。

DOM 二能够给某二个因素的同3个作为绑定三个区别的艺术

//实例 1
obj.addEventListener(事件类型 , 处理函数 , false)
//IE9以下不兼容,可以为一个事件绑定多个处理程序,并且按照绑定时的顺序去执行
//实例2
div.addEventListener('click' , function f() {} , false); //1
div.addEventListener('click' , function f() {} , false); //2
//事件1和事件2虽然执行的函数一样,但是函数f()的地址不一样,所以是2个处理函数,执行2次
//实例3
function f() {};
div.addEventListener('click' , f , false); //1
div.addEventListener('click' , f , false); //2
//事件1和事件2执行的函数都是f(),但因为地址一样,所以只执行一次。即某一个元素的同一个行为只能绑定一次相同的方法

大家应用的DOM贰事件绑定,其实是让box通过原型链平昔找到伊芙ntTarget那一个内置类原型上的add伊夫ntListener方法落成的。

大家采用的DOM二事件绑定,其实是让box通过原型链一直找到EventTarget那么些内置类原型上的add伊芙ntListener方法实现的。

js学习总括之dom二级事件基础知识详解,jsdom二

4858美高梅,大家应用的DOM贰事件绑定,其实是让box通过原型链从来找到伊芙ntTarget那一个内置类原型上的add伊芙ntListener方法完毕的。

DOM0级事件绑定:只好给三个因素的某多少个行事绑定2回艺术,第四回绑定的会把前边的掩盖掉。

DOM2:能够给某二个要素的同1个表现绑定多少个例外的法子

box.addEventListener('click',function(e){
      console.log(1)
    },false)
    box.addEventListener('click',function(e){
      console.log(2)
    },false) // 输出1 2

DOM二:DOM0中的行为类型,大家用DOM二均等能够绑定,而且DOM第22中学还提供了壹部分DOM0未有的一坐一起类型->DOMContentLoaded:当页面中的DOM结构(HTML结构加载成功)触发的作为

box.addEventListener('DOMContentLoaded',function(e){

    },false)

window.onload = function(){}

//当页面中的所有资源都加载完成(图片、HTML结构、音视频...)才会执行后面的函数;并且在一个页面中只能用一次,后面在写会把前面的覆盖掉;->因为他是采用DOM0事件绑定,所以只能绑定一次
     $(document).ready(function(){})//->$(function(){})
    /*
      只要页面中的HTML结构加载完成就会执行对应的函数;并且在同一个页面中可以出现多次。因此这个是采用DOM2事件的绑定,绑定的行为是DOMContentLoaded
    */

DOM2级增加和移除事件细节

function fn1(e){
      console.log(this);
    }
    //添加事件
    box.addEventListener('click',fn1,false);
    //移除事件
    box.removeEventListener('click',fn1,false);

注意:移除的时候供给确定保障多个参数:行为、方法、哪个阶段发生的   八个参数必须一律
->DOM二在绑定的时候,大家一般都给他绑定的是实名函数

只得给有些成分的同三个行事绑定多个“不同”的主意(即使艺术一致了,只可以留三个)

当作为触发,会依据绑定的先后顺序依次把绑定的不二秘诀实践;试行的this是眼前被绑定事件的因素本身

function fn1(){
      console.log(1);
    }
    //添加事件
    box.addEventListener('click',fn1,false);
    box.addEventListener('click',fn1,false);//只输出一个1

下面提到八个概念:事件池(用来存款和储蓄当前成分行为绑定的秘技的,浏览器自带的体制) 如下图所示

4858美高梅 1

 不过在IE6-八浏览器中,不帮忙add伊夫ntListener,要是想实现DOM二事件绑定只好用attach伊芙nt/detach伊芙nt

它唯有四个参数,不可能像add伊芙ntListener那样调整在哪个阶段产生,暗中认可只辛亏冒泡阶段产生,同时表现需求增添on(和DOM0尤其的近乎)

box.attachEvent('onclick',fn1)

注意:和标准浏览器的事件池机制比较:

1、顺序难题:实践的时候顺序是乱套的,标准浏览器是遵照绑定顺序依次履行的

二、重复难点:ie陆-捌足以给同四个要素的同一个表现绑定多个1律的章程

三、this难题:ie陆-第88中学当方法实践的时候,方法中的this不是当前的因素box而是window

以上正是本文的全体内容,希望对大家的学习抱有扶助,也愿意大家多多援救帮客之家。

大家使用的DOM二事件绑定,其实是让box通过原型链平昔找到伊夫ntTarget这么些内置类原型上的add伊夫nt…

1.1、DOMContentLoaded和loaded

DOM 二还提供了DOM 0中从未的行为类型 ->
DOMContentLoaded:当页面中的DOM结构(HTML结构)加载成功触发的作为。而onload事件则是当页面中的全体能源总体加载成功(图片、html结构、音摄像…)才会被实施。

jQuery中的$(document).ready(function () {}),等价于$(function ()
{}),事件规律就是DOM第22中学新扩张的DOMContentLoaded事件。

DOM0级事件绑定:只可以给二个要素的某三个行为绑定3遍艺术,首回绑定的会把前边的遮盖掉。

DOM0级事件绑定:只好给3个因素的某三个作为绑定一遍艺术,第一次绑定的会把前边的覆盖掉。

1.贰、事件的移除

DOM 0级事件的移除:div.onclick = null;

DOM 二级事件的移除:

function fn() {};
div.addEventListener('click',fn,false);
div.removeEventListener('click',fn,false);

DOM二:能够给某叁个成分的同3个表现绑定几个例外的方法

DOM二:能够给某一个因素的同二个表现绑定八个不相同的点子

一.3、DOM2事件机制

  • 不得不给某些成分的同多个行为绑定四个”差异”的不二秘技
  • 当作为触发,会绳趋尺步绑定的先后顺序把绑定的法子实行
  • 推行的点子中的this是当下绑定事件的因素本人
box.addEventListener('click',function(e){
      console.log(1)
    },false)
    box.addEventListener('click',function(e){
      console.log(2)
    },false) // 输出1 2
box.addEventListener('click',function(e){
            console.log(1)
        },false)
        box.addEventListener('click',function(e){
            console.log(2)
        },false) // 输出1 2

一.四、IE陆-八下的轩然大波机制

在IE陆-八浏览器中,不协助add伊芙ntListener/remove伊芙ntLiatener,要是想达成DOM
2事件绑定,只可以用attach伊夫nt(),移除用detach伊芙nt()。

 obj.attach伊芙nt(‘on’+type ,
func);只辛亏冒泡阶段发生,多少个轩然大波同样能够绑定五个管理函数。与obj.add伊夫ntListener(‘type’
, func , false)不雷同的是,即使函数的地址是均等的,绑定多少次就进行稍微次。即同2个函数能够绑定数次

与规范浏览器的事件池机制相比:

  • this难题:IE陆-第88中学当方法实践的时候,方法中的this不是当前因素,而指的是window
  • 再也难题:能够给同三个因素的同3个行事绑定八个同样的方法
  • 逐条难点:施行的时候顺序是无规律的,规范浏览器是依据绑定顺序依次推行

DOM2:DOM0中的行为类型,大家用DOM贰均等能够绑定,而且DOM第22中学还提供了有些DOM0没有的行为类型->DOMContentLoaded:当页面中的DOM结构(HTML结构加载成功)触发的作为

DOM二:DOM0中的行为类型,大家用DOM贰同等能够绑定,而且DOM2中还提供了部分DOM0未有的行事类型->DOMContentLoaded:当页面中的DOM结构(HTML结构加载成功)触发的表现

2、处理this问题

/*
 *    bind: 处理DOM2级事件绑定的兼容性问题
 *    @parameter:
 *    curEle: 要绑定事件的元素
 *    eventType: 要绑定的事件类型('click','mouseover'...)
 *    eventFn: 要绑定的方法
 */
 var tempFn = {};
 function bind(curEle,eventType,eventFn){
    if ("addEventListener" in document) {//标准浏览器
        curEle.addEventListener(eventType,eventFn,false);
        return ;
    }
    var tempFn[eventFn] = function () {
        eventFn.call(curEle);
    };
    curEle.attachEvent("on" + eventType,tempFn);
 }

 function unbind(curEle,eventType,eventFn) {
    if ("removeEventListener" in document) {
        curEle.removeEventListener(eventType,eventFn,false);
        return ;
    }
    curEle.detachEvent("on" + eventType,tempFn[eventFn]);
 }

//分析

// 1、知若想改变IE下事件执行函数的this的指向,可以在函数执行的时候改变this,即用函数eventFn.call('curEle'),这样虽然解决了this指向的问题,
   但又抛出了一个新的问题:即不知道该如何移除该事件函数,因为绑定的是一个匿名函数,而匿名函数的地址我们是无法知道的。
   所以要先把匿名函数定义时的地址赋值给一个变量temp
    var tempFn = function () {
        eventFn.call('curEle');
    };
//2、为什么要把tempFn设置成一个全局变量
    若tempFn不是一个全局变量,而是写在函数内部的私有变量,而私有变量只能在函数内部进行访问,
    所以我们在bind()函数里的tempFn在unbind()函数里是不能访问的,因此也就不能移除该事件函数。所以若想移除该事件函数,tempFn就必须是全局变量

拓展:咱俩驾驭:写在函数内部的变量是私有变量,二个函数的私人住房变量只辛亏函数的中间开始展览走访。

  • 若在叁个函数里要用到另三个函数里的变量,能够把该变量设置成全局的变量,那样四个函数都足以访问到。(那只怕会变成全局污染)
  • 若几个函数的效益是为同一个/同一类成分提供格局去行使,且区别措施中要用到别的措施里的变量等,那么能够用该因素的自定义变量来存款和储蓄这一个变量,就能够达成在分裂措施中的访问。(不会招致全局污染)

地点的代码除了全局变量可能形成污染外。还有一种不得不记挂的气象就是:当为区别的风浪绑定方法时,差异的风云也许施行同一的艺术(如mouseover
和 click
都实行fn一方法时),假诺如故将这么些方法囤积在壹块儿,那么移除某1类事件的方法时就可能出错,因而大家供给为分化的事件创制分裂的数组来囤积绑定在其上的办法。

据此大家供给对代码举办更加的优化。

function bind(curEle,eventType,eventFn){
        ...
        var tempFn = function () {
            eventFn.call('curEle');
        };
        tempFn.photo = eventFn;//给传入的每一个函数做一个唯一标识
        //首先判断该自定义属性之前是否存在,不存在的话创建一个,由于要存储多个方法,所以我们让其值是一个数组
        //为什么要对不同的事件类型创建不同的数组呢,因为不同的事件可能执行相同的方法。如mouseover 和 click 都执行fn1方法时,移除的时候就可能出错
        if (!curEle['bindFn' + eventType]) {
            curEle['bindFn' + eventType] = [];
        }
        curEle['bindFn' + eventType].push(tempFn);
        curEle.attachEvent("on" + eventType,tempFn);
    }

    function unbind(curEle,eventType,eventFn) {
        ...
        var arr = curEle['bindFn' + eventType];
        for (var i = 0; i < arr.length; i ++) {
            if (arr[i].photo === eventFn) {
                arr.splice(i,1);//找到后,把自己存储容器中对应的移除掉,与事件池中保持一致
                curEle.detachEvent("on" + eventType,arr[i]);//把事件池中对应的方法移除掉
                break;
            }
        }
    }
box.addEventListener('DOMContentLoaded',function(e){

    },false)


window.onload = function(){}

//当页面中的所有资源都加载完成(图片、HTML结构、音视频...)才会执行后面的函数;并且在一个页面中只能用一次,后面在写会把前面的覆盖掉;->因为他是采用DOM0事件绑定,所以只能绑定一次
     $(document).ready(function(){})//->$(function(){})
    /*
      只要页面中的HTML结构加载完成就会执行对应的函数;并且在同一个页面中可以出现多次。因此这个是采用DOM2事件的绑定,绑定的行为是DOMContentLoaded
    */
box.addEventListener('DOMContentLoaded',function(e){

        },false)

window.onload = function(){}//当页面中的所有资源都加载完成(图片、HTML结构、音视频...)才会执行后面的函数;并且在一个页面中只能用一次,后面在写会把前面的覆盖掉;->因为他是采用DOM0事件绑定,所以只能绑定一次
        $(document).ready(function(){})//->$(function(){})
        /*
            只要页面中的HTML结构加载完成就会执行对应的函数;并且在同一个页面中可以出现多次。因此这个是采用DOM2事件的绑定,绑定的行为是DOMContentLoaded
        */

三、管理重复难题

function bind(curEle,eventType,eventFn){
        if ("addEventListener" in document) {
            //省略代码
        }
        //省略代码
        //处理重复问题:如果每一次往自定义属性添加方法前,看一下是否已经有了,有的话就不用重复添加,同理,也就不用往事件池里存储了
        var arr = curEle['bindFn' + eventType];
        for (var i = 0; i < arr.length ;i ++) {
            if (arr[i].photo === eventFn) {
                return ;
            }
        }
        arr.push(tempFn);
        curEle.attachEvent("on" + eventType,tempFn);
    }

DOM二级增加和移除事件细节

DOM贰级加多和移除事件细节

肆、管理顺序难点

我们知道在IE6-⑧下,事件的施行顺序是冬天的,这是由浏览器的事件池机制所调整的。所以要更上一层楼那些主题素材,大家模仿正规浏览器的事件实践各样,能够友善写2个事变池来使方法的执行顺序有序推行。听起来有个别绕,我们来看一下具体的达成就掌握了。

  //创建自己的事件池,并把需要给当前元素绑定的方法依次增加到事件池中
    function on(curEle,eventType,eventFn) {
        if (!curEle['myEvent' + eventType]) {
            curEle['myEvent' + eventType] = [];
        }
        var arr = curEle['myEvent' + eventType];
        for (var i = 0; i < arr.length; i ++) {
            if (arr[i] === eventFn) return ;
        }
        arr.push(eventFn)
        bind(curEle,eventType,run);//把run方法绑定到自定义的bind()函数中,这个bind函数解决了this指向和重复问题。因此绑定后run方法的this指向当前点击元素
    }

   //在自己的事件池中把某一个方法移除
    function off(curEle,eventType,eventFn) {
        var arr = curEle['myEvent' + eventType];
        for (var i = 0; i < arr.length; i ++) {
            if (arr[i] === eventFn) {
                arr.splice(i,1);
            }
        }
    }

    //由于IE6-8浏览器DOM2级事件执行多个绑定方法时会出现顺序混乱,我们就只给它绑定一个run方法,然后在run方法里执行事件池on里绑定的方法。
    function run(event) {
        event = event || window.event;
        var flag = event.target ? true :false ;//IE6-8下不兼容event.target
        if (!flag) {//做非兼容处理
            event.target = window.srcElement;
            event.pageX = event.clientX + document.documentElement.scrollLeft;
            event.pageY = event.clentY +document.documentElement.scrollTop;
            event.preventDefault = function () {
                event.returnValue = false ;
            }
            event.stopPropagation = function () {
                event.cancleBubble = true ;
            }
        }
        //获取事件池中绑定的方法,并且让这些方法依次执行
        var arr = event.target['myEvent' + event.type];
        for (var i = 0; i < arr.length; i ++) {
            arr[i].call(event.target,event);//把事件对象传递给当前执行的函数
        }    
    }
function fn1(e){
      console.log(this);
    }
    //添加事件
    box.addEventListener('click',fn1,false);
    //移除事件
    box.removeEventListener('click',fn1,false);
function fn1(e){
            console.log(this);
        }
        //添加事件
        box.addEventListener('click',fn1,false);
        //移除事件
        box.removeEventListener('click',fn1,false);

伍、3个完好无损的DOM库

如上正是对包裹整个DOM库的思辨,可知分析的方方面面进程是多么的折磨。不过全体的DOM库封装后,代码却少的那多少个。大家一起来看一下。

//绑定事件
function on(ele,type,fn) {
    if(ele.addEventListener) {
        ele.addEventListener(type,fn,false);
    } else{
        if (!ele['myEvent' + type]) {
            ele['myEvent' + type] = [];
            ele.attachEvent('on' + type,function(){//在这里绑定run方法
                run.call(ele);
            })
        }
        let arr = ele['myEvent' + type];
        for(let i = 0; i < arr.length; i++) {
            if (arr[i] == fn) {
                return;
            }
        }
        arr.push(fn);
    }    
}

//解决IE下事件执行顺序的run方法
function run() {
    let e = window.event;//在IE6-8下,事件对象是存储在全局的event属性上的
    e.target = e.srcElement;
    e.preventDefault = function () {
        e.returnValue = false ;
    }
    e.stopPropagation = function () {
        e.cancleBubble = true ;
    }
    let arr = this['myEvent' + event.type];
    for(let i = 0; i < arr.length; i++) {
        if(arr[i] == null) {//在这里删除被解绑的方法
            arr.splice(i,1);
            i--;
        }
        arr[i].call(this,event);
    }
}

//解除事件
function off(ele,type,fn) {
    if (ele.removeEventListener) {
        ele.removeEventListener(type,fn,false);
    } else {
        let arr = ele["myEvent" + type];
        for(let i = 0; i < arr.length; i++) {
            if (arr[i] == fn) {
                arr[i] = null;
                //arr.splice(i,1);这里为什么不能直接删除掉,而是要用null来占位。答案是:为了不改变arr的长度。使run能正确执行。
                return;
            }
        }
    }
}

瞩目:移除的时候需求确认保障多个参数:行为、方法、哪个阶段发生的   八个参数必须一致
->DOM2在绑定的时候,我们一般都给她绑定的是实名函数

只顾:移除的时候需求保障多个参数:行为、方法、哪个阶段产生的   三个参数必须1律 ->DOM二在绑定的时候,我们一般都给他绑定的是实名函数

只可以给有些成分的同叁个行事绑定多少个“不同”的主意(若是艺术1致了,只好留三个)

不得不给有些成分的同贰个作为绑定多少个“分歧”的艺术(若是措施同样了,只好留3个)

当作为触发,会遵循绑定的先后顺序依次把绑定的办法实践;实行的this是眼下被绑定事件的成分本人

当作为触发,会循序渐进绑定的先后顺序依次把绑定的措施施行;执行的this是现阶段被绑定事件的要素本身

function fn1(){
      console.log(1);
    }
    //添加事件
    box.addEventListener('click',fn1,false);
    box.addEventListener('click',fn1,false);//只输出一个1
function fn1(){
            console.log(1);
        }
        //添加事件
        box.addEventListener('click',fn1,false);
        box.addEventListener('click',fn1,false);//只输出一个1

上边提到一个概念:事件池(用来储存当前成分行为绑定的点子的,浏览器自带的编写制定) 如下图所示

上边提到二个概念:事件池(用来积存当前因素行为绑定的不2法门的,浏览器自带的体制)
如下图所示

4858美高梅 2

4858美高梅 3

 不过在IE6-8浏览器中,不帮衬add伊夫ntListener,就算想完毕DOM二事件绑定只可以用attach伊芙nt/detach伊芙nt

 

它唯有几个参数,不能像add伊夫ntListener那样调控在哪些阶段产生,暗中认可只幸而冒泡阶段爆发,同时作为必要增添on(和DOM0越发的类似)

但是在IE六-八浏览器中,不扶助add伊夫ntListener,借使想实现DOM二事件绑定只好用attach伊芙nt/detach伊芙nt

box.attachEvent('onclick',fn1)

它唯有三个参数,无法像add伊芙ntListener那样调整在哪个阶段发生,私下认可只辛亏冒泡阶段爆发,同时表现须求增加on(和DOM0尤其的好像)

注意:和专门的工作浏览器的事件池机制相比较:

box.attachEvent('onclick',fn1)

1、顺序难题:实行的时候顺序是乱套的,标准浏览器是比照绑定顺序依次实施的

小心:和行业内部浏览器的事件池机制相比:

贰、重复难点:ie陆-8足以给同三个因素的同1个表现绑定七个一样的法子

一、顺序难题:施行的时候顺序是无规律的,规范浏览器是比照绑定顺序依次实行的

三、this难题:ie陆-第88中学当方法施行的时候,方法中的this不是当前的因素box而是window

二、重复难点:ie六-八能够给同一个要素的同三个行为绑定多个1律的点子

上述便是本文的全体内容,希望对大家的学习抱有扶助,也可望大家多多帮忙脚本之家。

叁、this难点:ie6-第88中学当方法试行的时候,方法中的this不是当前的元素box而是window

您恐怕感兴趣的稿子:

  • JS中dom0级事件和dom二级事件的区分介绍
  • 部分主流JS框架中DOMReady事件的贯彻小结
  • JavaScript DOM 增添事件
  • Javascript
    Event事件中IE与标准DOM的比较
  • javascript
    删除dom对象的轩然大波函数代码
  • DOM3中的js
    textInput文技巧件
  • JS、CSS以及img对DOMContentLoaded事件的熏陶
  • Javascript封装DOMContentLoaded事件实例
  • JavaScript DOM事件(笔记)
  • 有关javascript
    DOM事件模型的两件事

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 美高梅手机版4858 版权所有