移动端_Day3

一、事件深入

1.1、事件流

比如说有一个父子盒模型,同时都有点击事件。当你点击了子元素元素,这个点击事件不仅仅发生在子元素的身上,也发生在父元素的身上,此时的整个点击事件的经过,就是一个事件流。

<script>
    var div = document.querySelector("div");
    var p = document.querySelector("p");
    p.onclick = function(){
        alert("我是子盒子");
    };
    div.onclick  = function(){
        alert("我是父盒子");
    };
    document.body.onclick = function(){
        alert("我是body标签")
    };
    document.odocumentElement.onclick = function(){
        alert("我是html标签");
    };

document.onclick = function(){ alert("我是document标签"); };
   window.onclick = function(){ alert("我是window标签"); };
</script>

 从子盒子向外冒泡触发事件。

我们为了描述事件流的执行顺序,特意分为了两个阶段:捕获阶段、冒泡阶段

1.2、DOM0级别事件绑定。

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

 之前学习的事件绑定类型

oDiv.onclick=function(){}

之前写的是注册方法,这个是DOM0级事件。就是把onclick当做属性添加给了oDiv元素。

执行过程分别是子元素→父元素→body→html(documentElement)→document→window

通过实验我们发现,DOM0级事件绑定方法,只监听的是冒泡阶段,事件的捕获阶段没有监听

在IE9和Chrome中,事件会冒泡到window对象,而IE6,7,8仅仅会冒泡到document对象。

****************自定义函数属性在DOM中的写法*************************

<script>
    var box1 = document.querySelector(".box1");
    box1.onmouseenter = changeRed;
    box1.onmouseleave = changeBlue;
    function changeRed(){
        this.style.backgroundColor="red";
    };
    function changeBlue(){
        this.style.backgroundColor="skyblue";
    };
</script>

使用DOM0级触发的事件监听,this指的就是当前被触发的元素本身。

<div class="box1" onclick="alert('我是box1')">
    <div class="box2" onclick="alert('我是box2')">
        <div class="box3" onclick="alert('我是box3')">

        </div>
    </div>
</div>

DOM0级还有一种写法, 就是将事件写到了标签上,同样的只监听冒泡阶段(这种写法不建议)

box.onclick = function() {
    alert("触发2")
}
box.onclick = function() {
    alert("触发1")
}

DOM0级事件中,同一个元素如果设置了两个同样的事件监听,后写的会覆盖先写的执行(并不会累加执行)

box.onmouseenter = function() {
    alert("触发1")
}
box.onmouseover = function() {
    alert("触发2")
}

因为onmouseover的事件优先级高,所以会先执行“触发2”然后紧接着执行“触发1”

1.3、DOM2级事件

DOM1级规范中,没有对事件进行改动

DOM3级事件中,主要是html新增的api和自定义事件,以及触发事件等等,这些都不是我们移动端课程的主要内容,也不是事件流的主体

DOM2级事件做了新的规范,不用on***来监听事件了,而是增加了一个方法

addEventListener()

add增加

Event事件

Listener监听

它一共接受3个参数,分别是事件内容(加双引号)、函数主体、是否监听捕获阶段。不同的参数之间用逗号隔开。

第一个参数:事件名称,注意不用写on,比如click,mouseenter等,注意要用双引号

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

第三个参数:false:监听冒泡阶段 true:监听捕获阶段。

移除事件用removeEventListener();

<script>
    var div = document.querySelector("div");
    var p = document.querySelector("p");
    p.addEventListener("click",function(){
        alert("我是字元素,捕获阶段");
    },true);
    div.addEventListener("click",function(){
        alert("我是父元素,捕获阶段")
    },true);
    document.body.addEventListener("click",function(){
        alert("我是body元素,捕获阶段")
    },true);
    document.documentElement.addEventListener("click",function(){
        alert("我是html元素,捕获阶段")
    },true);
    document.addEventListener("click",function(){
        alert("我是document元素,捕获阶段")
    },true);
    window.addEventListener("click",function(){
        alert("我是window元素,捕获阶段")
    },true);
    p.addEventListener("click",function(){
        alert("我是子元素,冒泡阶段")
    },false);
    div.addEventListener("click",function(){
        alert("我是父元素,冒泡阶段")
    },false);
    document.body.addEventListener("click",function(){
        alert("我是body元素,冒泡阶段")
    },false);
    document.documentElement.addEventListener("click",function(){
        alert("我是html元素,冒泡阶段")
    },false);
    document.addEventListener("click",function(){
        alert("我是document元素,冒泡阶段")
    },false);
    window.addEventListener("click",function(){
        alert("我是window元素,冒泡阶段")
    },false);
</script>

l  需要注意的是如果被触发的元素是自己,不区分捕获或者冒泡阶段,只会按照书写顺序执行

比如说只有一个元素绑定事件,点击之后是按书写顺序执行。

当事件触发在目标阶段时,会根据事件注册的先后顺序执行,在其他两个阶段注册顺序不影响事件执行顺序。也就是说如果该处既注册了冒泡事件,也注册了捕获事件,则按照注册顺序执行。

<script>
    var div = document.querySelector("div");
    var p = document.querySelector("p");
    p.addEventListener("click",function(){
        alert("p,冒泡")
    },false);
    p.addEventListener("click",function(){
        alert("p,捕获")
    },true);
    div.addEventListener("click",function(){
        alert("div,冒泡")
    },false);
    div.addEventListener("click",function(){
        alert("div,捕获")
    },true);
</script>

 若点击子盒子,则此处的运行顺序应该是div捕获,p冒泡,p捕获,div冒泡,是因为该处既注册了冒泡事件,也注册了捕获事件,则按照注册顺序执行。

若使用谷歌浏览器则还是按照捕获-冒泡的顺序,若使用IE浏览器才会出现上述结果,是由于浏览器的兼容性问题。

DOM2级中this的指向问题

和DOM0级一样,也是指向触发元素本身。

当我们给一个元素绑定两个相同的事件监听时,会按照书写顺序执行两次,不会像DOM0级那样覆盖。

box.addEventListener('click', function() {
    alert("触发2")
}, false)
box.addEventListener('click', function() {
    alert("触发1")
}, false)

 如果设置同一个元素不同的事件,和DOM0级一样会按照事件的优先级顺序来执行。

1.4、低版本IE浏览器的事件绑定

低版本IE一直有兼容问题,我们的事件绑定也不例外

IE6,7,8不支持addEventListener()方法,用attachEvent()和deattachEvent()方法来添加或者移除事件,只有两个参数,一个是添加的参数(注意加on),一个是函数。

nP.attachEvent("onclick", function() {
    
})

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

第二个参数就是事件函数

没有第三个参数,因为只能监听冒泡阶段,所以写法和on***一样

 

低版本IE浏览器的this指向问题。

我们会发现低版本IE的this指向的是window。

function changeRed() {
            alert(this == window)
}

接下来讨论同样的元素设置同样的事件。

box.attachEvent('onmouseenter', function() {
    alert("触发3")
})
box.attachEvent('onmouseenter', function() {
    alert("触发2")
})
box.attachEvent('onmouseover', function() {
    alert("触发1")
})

 也会分别执行,但是会倒置执行,分别是触发1,触发2,触发3.

接下来讨论同样元素设置不同事件。

 如果设置同一个元素不同的事件,和DOM0级一样会按照事件的优先级顺序来执行。

1.5,事件轮子。

我们需要封装一个方法,兼容高版本和低版本浏览器,主要是低版本的attachEvent和高版本addEventListener两个方法的兼容

<script>
    //声明一个函数addEvent,有三个参数
    // 第一个参数obj指定要绑定事件的元素
    // 第二个参数eventtype指的是事件名称,在这里不加on,需要加on的时候再用字符串的拼接
    // 第三个参数就是处理函数fn
    function addEvent(obj,eventtype,fn){
        // 判断该元素所在的浏览器支持哪一种事件绑定的方法
        if(obj.addEventListener){
            // 如果该元素所在的浏览器支持addEventListener
            obj.addEventListener(eventtype,fn,false);
        }else if(obj.attachEvent){
            // 如果该元素所在的浏览器支持attachEvent的方法
            // 注意此时需要加"on"+eventtype
            obj.attachEvent("on"+eventtype,function(){
                // 因为低版本浏览器的this是指向window的,所以需要单独设置属性让它指向该元素
                // call指的是将函数上下文this指向call里面的元素
                fn.call(obj);
            })
        }else{
            // obj['key']此时key代表的是obj的一个属性名,需要加上''使用,obj['key']———取obj的key属性的值
            obj["on"+eventtype] = fn;
        }
    }
    var div = document.querySelector("div");
    addEvent(div,"click",function(){
        this.style.backgroundColor = "red";
    })
</script>

 

我们把所有之前学习的事件流进行一个总结

事件流是先下后上,先捕获后冒泡。但是不同的添加监听的方式,决定了能监听的那一部分

  • DOM0级,只能监听冒泡阶段。不能有同名事件,否则会覆盖。this指向的是被触发的内个元素。高版本浏览器会冒泡到window,但是IE8及以下会冒泡到document
  • DOM2级,addEventListener,可以自由设置捕获和冒泡,第三个参数如果是false则代表冒泡,true代表捕获。事件名不加on,如果有同名事件,不会覆盖会依次执行。this指的是触发事件的元素。会冒泡到window
  • IE6,7,8使用的是自己的方法attachEvent,只能监听冒泡阶段。没有第三个参数。事件名需要写on,可以有同名事件,但是会反向执行。this指向的是window,冒泡只冒泡到document阶段

二、事件委托 target属性

什么是事件委托?当页面中很多个同样 的盒子都添加了事件监听,此时如果按照我们传统的想法,就是给所有的盒子都添加事件监听

<script>
    // 事件委托,如果给所有的div添加监听,此时利用他们的父亲body委托执行
    document.body.onclick = function(event){
    // event.target指的是被触发事件的目标对象,所以下面的代码指的就是被触发事件的目标对象(元素)样式的背景颜色为红色
      event.target.style.background = "red";  
    }
</script>

target指的就是event事件对象的target属性,属性值指的就是被触发的目标对象

事件委托的原理其实就是利用事件冒泡,将事件冒泡给祖先元素https://www.webhek.com/post/event-delegate.html

<script>
    var btn = document.querySelector(".btn");
    var box = document.querySelector(".box");
    btn.onclick = function(){
    //用JS动态创建元素的方法
    var oP = document.createElement("p");
    //将节点加到节点树里面
    box.appendChild(oP);
    }
    //如果此时要动态的将某一个不确定的盒子的样式改变,则通过传统方法很难以捕捉到目标盒子,这时就可以用事件委托
    box.onclick = function(event){
        event.target.style.background = "green";
    }
</script>

 下面介绍低版本IE的兼容性问题,在低版本ie中不支持target属性,所以需要使用兼容性写法。

document.body.onclick = function(event) {
     window.event.srcElement.style.backgroundColor = 'orange'
}

 兼容写法如下:

// 事件委托,如果给所有的div添加监听,此时利用他们的父亲body委托执行
document.body.onclick = function(event) {
    // 能力判断,如果有event对象,就获取targe属性,没有就获取window对象的SrcElement属性
    var event = event || window.event;
    var ele = event.target || event.srcElement;
    ele.style.backgroundColor = 'orange'
}

 三、阻止事件传播

我们在前面的课程中学习了,事件流,事件会有捕获和冒泡,此时我们希望阻止事件传播

有一个父子盒子nDiv和nP,此时正常如果都设置了点击事件,会出现事件冒泡,所以此时我们给子盒子设置 event.stopPropagation()方法,会阻止事件冒泡

nP.onclick = function(event) {
    // stopPropagation方式是event实际中阻止事件流传播的方法
    event.stopPropagation()
    this.style.background = 'pink'
}
nDiv.onclick = function() {
    alert("我是父元素")
}

最后只会让子盒子nP的颜色变为粉色,父盒子不会弹出alert

DOM0级和DOM2级事件都是同样的方法组件事件传播,详情见案例

 

注意IE低版本浏览器的兼容性问题。

nP.onclick = function(event) {
    // 低版本ie8以下兼容的组织事件冒泡的写法
    window.event.cancelBubble = true;
    this.style.background = 'pink'
}

 兼容写法如下:

nP.onclick = function(event) {
    // 短路语法进行兼容
    var event = event || window.event;
    if (event.stopPropagation) {
        // 高版本浏览器
        event.stopPropagation()
    } else {
        // 兼容ie8以下的低版本
        event.cancelBubble = true;
    }
    this.style.backgroundColor = "blue"
}

 

posted @ 2022-01-15 10:47  Viper7  阅读(37)  评论(0)    收藏  举报