我tm是万万没想到这么简单的JS demo会踩坑,而且踩坑的点是在CSS盒子层次的问题。经过逐行对照案例的JS、HTML、CSS,才发现是我CSS少了一句position:absolute,导致原本期望在上面的盒子(ul)被另一个绝对定位的盒子(span.cloud)压住。

简化了一下代码:

<!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>
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        nav {
            position: relative;
            width: 500px;
            height: 70px;
            margin: 100px auto 0;
            background-color: grey;
        }

        .cloud {
            z-index: 1;
            position: absolute;
            top: 50%;
            left: 0;
            transform: translateY(-50%);
            width: 50px;
            height: 30px;
            background-color: green;
            opacity: 0.4;
        }

        ul {
            z-index: 2;
            position: absolute;
            list-style: none;
            /* background-color: pink; */
            /* opacity: 1; */
        }

        ul li {
            float: left;
            padding: 20px;
        }
    </style>
</head>

<body>
    <nav>
        <!-- cloud 作为背景,放在下层,先书写 -->
        <!-- <span class='cloud'></span> -->
        <!-- ul必须由宽高才能在层次上遮挡cloud,但要透明才能在视觉上显示cloud背景 -->
        <!-- 这个宽高遮挡作用不能由li代替,li级别不如span -->
        <ul>
            <li><a href="javascript:;">abcde</a></li>
            <li><a href="javascript:;">abcde</a></li>
            <li><a href="javascript:;">abcde</a></li>
            <li><a href="javascript:;">abcde</a></li>
            <li><a href="javascript:;">abcde</a></li>
            <li style="float: none; padding: 0;clear:both;"></li>
        </ul>
        <!-- cloud 作为背景,如写在后面,需要z-index调整到下面 -->
        <span class='cloud'></span>
    </nav>
    <script>
        window.addEventListener('load', function () {
            var nav = document.querySelector('nav');
            var ul = document.querySelector('ul');

            nav.addEventListener('mouseover', function (e) {
                console.log(['mouseover', e.target.tagName]);
            });

            nav.addEventListener('mouseout', function (e) {
                console.log(['mouseout', e.target.tagName]);
            });
        });
    </script>
</body>

</html>

目标:正常的、不会干扰JS代码的盒子层次,应该是:nav在最底部,往上是cloud,再往上是ul,ul的子元素li自然更高一点。主要是ul在盒子层次上要比cloud高,层次上能够遮挡;同时注意视觉上是透明的,可以看到底下的cloud。

验证:当然,上面说的都是盒子堆叠的层次,要验证这个层次是否正确,还得利用事件流父子层次(mouseover/mouseout监听并打印事件的target)。
如果盒子堆叠的层次正确,将鼠标移动到ul、li上只会触发nav、ul、li、a,而不会触发cloud,因为ul和cloud是兄弟而且要把cloud压在下面。形成的冒泡事件流就是:a->li->ul->nav。
注意,即使li有高度而ul无高度(li浮动、应该clearfix或强制给ul设置高度),li是不能代替ul去压住cloud的。这时候冒泡事件流:a->li/cloud->nav,混杂了cloud进来,cloud反而会压住li、a,从而导致li触发的mouseover退出转为mouseout。


BENCJL
15 声望0 粉丝

问天问大地