JavaScript阶段易踩坑--层级覆盖--var与let使用--事件流(捕获和冒泡)

刚刚走完JavaScript阶段,感觉挺爽的。但在总结的时候,我发现一些在做网页中容易错的地方,还有一些比较重要的方面。为了避免其他人在这一阶段也遇到这些问题。我今天就着重说一下在JavaScript这一阶段我容易出现的问题,从而让大家在遇到相同问题的时候可以快速解决。

一.盒子覆盖问题

只要我们做网页总会发生盒子覆盖的问题。我们在下HTML样式的时候没有注意各个盒子的层级关系,导致一些上层盒子放在了下面。当我们在 js 中通过document来获取盒子进行一些操作如:点击事件。

  var boy = document.querySelector('.boy');
   boy.addEventListener('click', function() {
      boy.style.background="red"
    })

我们获取到盒子后对它注册点击事件,点击后,盒子的背景颜色变成红色。但如果这个 boy 的盒子被其他盒子覆盖,我们及时获得盒子并注册点击事件也不能对它进行我们想要的操作。解决的办法就是提升这个盒子的层级,让我们的鼠标可以点击到我们注册监听的盒子。这一部分容易被大家遗忘,如果出现使用js获取某一元素但不能进行想要的操作的时候,我们可以检查一下自己的盒子的层级关系。

二.var 和 let 的正确使用

我们走JavaScript这一阶段的时候varlet的区别与联系一定要理解透彻,否则在使用的时候就容易出现一个错误。

相似点:

局部变量:在函数体内使用 var 和 let 关键字声明的变量有点类似。它们的作用域都是 局部的:
全局变量:在函数体内或则代码块外使用 var 和 let 关键字声明的变量有点类似。它们的作用域都是 全局的:

不同点:

1.在 HTML 中, 全局作用域是针对 window 对象。使用 var 关键字声明的全局作用域变量属于 window 对象:使用 let 关键字声明的全局作用域变量不属于 window 对象:
2. 在相同的作用域或块级作用域中,不能使用 let 关键字来重置 var 关键字声明的变量,var可以重置var关键紫的变量。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <h2>使用 var 声明变量</h2>
    <p id="demo"></p>
    <script>
        var x = 10;
        // 这里输出 x 为 10
        {
            var x = 2;
            // 这里输出 x 为 2
        }
        // 这里输出 x 为 2
        document.getElementById("demo").innerHTML = x;
    </script>
    </body>
    </html>
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <h2>使用 let 声明变量</h2>
    <p id="demo"></p>
    <script>
        var x = 10;
        // 这里输出 x 为 10
        {
            let x = 2;
            // 这里输出 x 为 2
        }
        // 这里输出 x 为 10
        document.getElementById("demo").innerHTML = x;
    </script>
    </body>
    </html>
  1. 在相同的作用域或块级作用域中,不能使用 let 关键字来重置 let 关键字声明的变量:
    在相同的作用域或块级作用域中,不能使用 var 关键字来重置 let 关键字声明的变量:
    let 关键字在不同作用域,或不同块级作用域中是可以重新声明赋值的:
<h2>JavaScript let</h2>
    <p id="demo"></p>
    <script>
        var i = 5;
        for (let i = 0; i < 10; i++) { //  使用 let 关键字, 它声明的变量作用域只在循环体内,循环体外的变量不受影响。
            // 一些代码...
        }
                //这里输出的是 10;
        document.getElementById("demo").innerHTML = i;
    </script>
    <h2>JavaScript let</h2>
    <p id="demo"></p>
    <script>
        var i = 5;
        for (let i = 0; i < 10; i++) { //  使用 let 关键字, 它声明的变量作用域只在循环体内,循环体外的变量不受影响。
            // 一些代码...
        }
                        //这里输出的是 10;
        document.getElementById("demo").innerHTML = i;
    </script>

三.DOM 事件流 三个阶段

1.JS 代码中只能执行捕获或则冒泡其中的一个阶段;
2.像onclick 和 attachEvent(ie) 这些事件只能得到冒泡阶段。

DOM事件流

1.事件流描述的是从页面中接受时间的顺序;
2.事件发生时会在元素节点之间按照特定的顺序传播 这个传播的过程即DOM事件流。

比如我们给一个div注册一个点击事件:
1.捕获阶段
2.当前目标阶段
3.冒泡阶段

这就是dom事件流的流程图
冒泡事件:IE最早提出的,事件开始的时候由最具体的元素进行接收,然后逐级向上传播到DOM最顶层节点的过程。
事件捕获:网景最早提出,由DOM最顶层的节点开始,然后逐级往下传播到最具体的元素接受的过程。

我们可以这样理解:我们向水里扔一块石头,首先它会有一个下降的过程,这个过程就可以理解为从顶层向事件发生的最具体元素(目标点)的捕获过程;之后会产生泡泡,会在最低点(最具体元素)之后漂浮到水面上,这个过程就相当于事件冒泡。

我们可以通过代码来更深了解捕获阶段和冒泡阶段:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div class="father">
        父亲
        <div class="son">儿子</div>
    </div>
 <script>
       // 3.捕获阶段 如addEventLister 第三个参数是 true 那么则处于捕获阶段 document ->HTML->body->father->son
        var son = document.querySelector('.son');
        var father = document.querySelector('.father');

        son.addEventListener('click', function() {
            alert("son");
        }, true);
        father.addEventListener('click', function() {
            alert("father");
        }, true);

        // 4.冒泡阶段 如addEventLister 第三个参数是 false 那么则处于冒泡阶段 son->father->body->HTML-> documentson
        var son = document.querySelector('.son');
        var father = document.querySelector('.father');

        son.addEventListener('click', function(e) {
            alert("son");
          //  e.stopPropagation();
        }, false);
        father.addEventListener('click', function(e) {
            alert("father");
        }, false);
        document.addEventListener('click', function(e) {
            alert("document");
        }, false);
    </script>
    </body>
    </html>

根据上面的代码我进行展开解释:

我们写一个father盒子,然后在father盒子里面写一个son盒子;给两个盒子都注册点击监听事件,当点击相对应的盒子的时候,弹出对应盒子的警告框。

addEventLister 第三个参数是 true 那么则处于捕获阶段,addEventLister 第三个参数是 false 那么则处于冒泡阶段。

我们先将第三个参数写成true处于捕获阶段,来看一下捕获阶段的事件流。当我们只执行捕获阶段时,我们执行代码点击son盒子。我们发现第一个出现的是father的警告框,然后才是son的警告框。这一阶段就是捕获阶段。

然后我们在将第三个参数改成false处于冒泡阶段,来看一下冒泡阶段的事件流。当我们只执行冒泡阶段,我们执行代码块点击son盒子。son盒子的警告框弹出,然后是father和document的警告框。这一阶段就是冒泡阶段。

解决冒泡的的方法:

冒泡事件常会导致一些其他的问题,如:我对网页中的某一模块进行滚轮监听,然后我的整个网页也有一个滚轮监听,当我对某一模块进行滚轮事件的之后页面也在进行滚轮事件。对网页的制作有很大的影响,这个时候我们就要想一下解决方法了。其实解决的办法很简单,该属性阻止冒泡即可。通常我们做项目话都会使用

e.stopPropagation();

来阻止某一阶段的冒泡阶段,如我上面的冒泡阶段写的阻止son的冒泡。但只是阻止了son的冒泡,如果我点击father盒子出现警示框之后document的警示框还是会出来。所以大家在使用的时候要注意。
它还有一个弊端就是不适应ie6-ie8的浏览器。如果你想考虑兼容性可以加上

e.cancelBubble;

来取消冒泡。
注意:
1.实际开发中我们很少使用事件捕获,我们更加关注事件冒泡。
2.有些事件是没有冒泡的。比如:onblur, onfocus,onmouseenter,onmouseleave
3.事件冒泡有时候会带来麻烦,有时候又会很有帮助巧妙地做某些事。

这就是我走完JavaScript阶段后认为比较重要的三点。大家可以参考一下。如果有错误,希望大家之处。我们一起进步。中间有不懂得地方可以留言。我看后回应。

猜你喜欢

转载自blog.csdn.net/weixin_51261234/article/details/114008854
今日推荐