js中嵌套for循环this指向问题-求解答?

有一个li列表;每点击一个li,会将每个li的子节点span复制到一个div里面,但div只显示当前所点击的li的下面的子节点,其他的都隐藏。

现在遇到的问题是,按照li的顺序点击,可以正常执行,打乱顺序点击,div内显示的会错乱。

目前我自测问题是,li的长度点击前已经获取到,但div内显示li子节点的长度是未知的,按照顺序点击
div内复制的span时的index是和li同步的,如果打乱顺序,譬如第一个点击的<li>2</li>(即this.index为1),但div内这是第一次复制,一个index为1一个还是0导致创建的节点不一样。

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>test</title>
    <style>

        li {
            list-style-type: none;
        }

        ul li {
            width: 300px;
            height: 20px;
            border: 1px solid #663333;
            margin-bottom: 5px;
            text-align: center;
        }

        #div1 {
            width: 300px;
            height: 100px;
            margin-left: 40px;
            border: 1px solid rebeccapurple;
        }

        #div2 {
            width: 150px;
            height: 100px;
            background-color: #954b4b;
            margin: 0 auto;
            text-align: center;
            line-height: 100px;
            color: white;
            display: none;
        }

    </style>

</head>
<body>
<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
</ul>
<div id="div1">
    <div id="div2"></div>
</div>


<script>
    window.onload = function () {
        var ul_li = document.getElementsByTagName('li');
        var div2 = document.getElementById('div2');

        function getStyle(obj, attr) {
            if (obj.currentStyle) {
                return obj.currentStyle[attr];
            }
            else {
                return getComputedStyle(obj, false)[attr];
            }
        }
        //

        for (var i = 0; i < ul_li.length; i++) {
            ul_li[i].index = i;
            ul_li[i].onclick = function () {
                if (getStyle(div2, 'display') === 'none') {
                    div2.style.display = 'block';
                }
                //debugger;
                if (!this.getAttribute('index')) {
                    this.setAttribute('index', this.index);
                    var new_span = document.createElement('span');
                    var new_span_text = document.createTextNode(ul_li[this.index].innerHTML);
                    div2.appendChild(new_span);
                    new_span.appendChild(new_span_text);
                    new_span.className = 'span_class';
                }
                //
                var t_lenght = document.getElementsByClassName('span_class');
                for (var j = 0; j < t_lenght.length; j++) {
                    t_lenght[j].id = j;
                    t_lenght[j].style.display = 'none';
                    var x = j;
                }
                //debugger;
                t_lenght[this.index].style.display = 'block';
            }
        }

        div2.onclick = function () {
            if (getStyle(div2, 'display') === 'block') {
                div2.style.display = 'none';
            }
        }
    }
</script>
</body>
</html>
阅读 3.9k
2 个回答

为何不在一开始就渲染好节点,然后在点击时候只是处理display的逻辑呢?

或是在4个全部被点击前使用最后一个显示,然后在全部被点击后将其排序。

或是在创建节点时候,维护一个数组,即是被点击的li的索引值,用来转换。

我只是把你for循环的一部分内容给改动了,既然你一定要使用 index 结合 id 来做,那我就用你的方式来做。

你的代码中最显著的问题是:

index 没有和 id 正确的绑定在一起,也就是说,如果你先点击第四个,则index = 3 的时候,你的 id 是 0 。

出现这个问题的原因也很明显,就是你在绑定的方式的是错误的。

你的绑定,是在创建div>span之后,循环span list,然后绑定这是每一个span的id。这会导致,你先点击 index = 3,然后创建一个 span,循环span,因为只有一个,设置这个span#id 为 0。

我的代码中,最大的改变就是 new_span.id = this.index; 这样绑定id,然后下面循环控制显示即可。

给你一个预览:https://jsfiddle.net/jsxo6kfq/ 进去之后可以看看效果

window.onload = function () {
            var ul_li = document.getElementsByTagName('li');
            var div2 = document.getElementById('div2');

            function getStyle(obj, attr) {
                if (obj.currentStyle) {
                    return obj.currentStyle[attr];
                }
                else {
                    return getComputedStyle(obj, false)[attr];
                }
            }
            //
            for (var i = 0; i < ul_li.length; i++) {
                ul_li[i].index = i;
                ul_li[i].onclick = function () {
                    if (getStyle(div2, 'display') === 'none') {
                        div2.style.display = 'block';
                    }
                    //debugger;
                    if (!this.getAttribute('index')) {
                        this.setAttribute('index', this.index);
                        var new_span = document.createElement('span');
                        var new_span_text = document.createTextNode(ul_li[this.index].innerHTML);
                        div2.appendChild(new_span);
                        new_span.appendChild(new_span_text);
                        new_span.className = 'span_class';
                        new_span.id = this.index;
                    }
                    //
                    var t_lenght = document.getElementsByClassName('span_class');
                    for (var j = 0; j < t_lenght.length; j++) {
                        if (t_lenght[j].id != this.index) {
                            t_lenght[j].style.display = 'none';
                        } else {
                            t_lenght[j].style.display = 'block';
                        }
                    }
                }
            }

            div2.onclick = function () {
                if (getStyle(div2, 'display') === 'block') {
                    div2.style.display = 'none';
                }
            }
        }
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题