tabList[i] 直接写“i”不行的原因:点击LI把绑定的函数执行,在形成的私有上下文中,遇到的变量“i”不是私有的,而是其上级上下文「EC(G)全局」的;而此时全局的“i”,已经是循环最后的结果3…

  1. //获取所有li元素 div元素
  2. var tabList = document.querySelectorAll(".tabox .tab>li"),
  3. conList = document.querySelectorAll(".tabox .content>div");
  4. var prevIndex=0;
  5. for(var i=0;i<tabList.length;i++){
  6. item.onclick=function(){
  7. tabList[i].className='active'
  8. }
  9. }

终极方案:事件委托 推荐指数 *

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>Document</title>
  8. <style>
  9. * {
  10. margin: 0;
  11. padding: 0;
  12. }
  13. ul,
  14. ol {
  15. list-style: none;
  16. }
  17. .tabox {
  18. margin: 20px auto;
  19. width: 500px;
  20. }
  21. .tabox .tab {
  22. display: flex;
  23. position: relative;
  24. top: 1px;
  25. }
  26. .tabox .tab li {
  27. padding: 10px 20px;
  28. background-color: #eee;
  29. border: 1px solid #bbb;
  30. margin-right: 10px;
  31. cursor: pointer;
  32. }
  33. /* 选中样式 白色背景 下边框白色 */
  34. .tabox .tab li.active {
  35. background-color: #fff;
  36. border-bottom-color: #fff;
  37. }
  38. .content div {
  39. width: 400px;
  40. height: 150px;
  41. border: 1px solid #bbb;
  42. padding: 5px;
  43. box-sizing: border-box;
  44. display: none;
  45. }
  46. .content div.active {
  47. display: block;
  48. }
  49. </style>
  50. </head>
  51. <body>
  52. <div class="tabox">
  53. <ul class="tab">
  54. <li class="active" index="0">电视剧</li>
  55. <li index="1">电影</li>
  56. <li index="2">综艺</li>
  57. </ul>
  58. <div class="content">
  59. <div class="active">你是我的城池营垒</div>
  60. <div>我的姐姐</div>
  61. <div>怦然心动</div>
  62. </div>
  63. </div>
  64. <script>
  65. let tabBox = document.querySelector('.tabox'),
  66. tabList = tabBox.querySelectorAll('.tab li'),
  67. conList = tabBox.querySelectorAll('.content div');
  68. let prevIndex = 0;
  69. // 不论点击哪一个LI,盒子的点击事件行为也会触发,对应方法执行,ev是事件对象,存储了当前操作的信息
  70. tabBox.onclick = function (ev) {
  71. let target = ev.target; //事件源
  72. if (target.tagName === "LI") {
  73. // 点击的是LI:基于getAttribute获取自定义属性「它的索引」
  74. let index = +target.getAttribute('index');
  75. if (index === prevIndex) return;
  76. tabList[index].className = conList[index].className = 'active';
  77. tabList[prevIndex].className = conList[prevIndex].className = '';
  78. prevIndex = index;
  79. }
  80. };
  81. </script>
  82. </body>
  83. </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>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        ul,
        ol {
            list-style: none;
        }

        .tabox {
            margin: 20px auto;
            width: 500px;
        }

        .tabox .tab {
            display: flex;
            position: relative;
            top: 1px;
        }

        .tabox .tab li {
            padding: 10px 20px;
            background-color: #eee;
            border: 1px solid #bbb;
            margin-right: 10px;
            cursor: pointer;
        }

        /* 选中样式  白色背景 下边框白色 */

        .tabox .tab li.active {
            background-color: #fff;
            border-bottom-color: #fff;
        }

        .content div {
            width: 400px;
            height: 150px;
            border: 1px solid #bbb;
            padding: 5px;
            box-sizing: border-box;
            display: none;
        }

        .content div.active {
            display: block;
        }
    </style>
</head>

<body>
    <div class="tabox">
        <ul class="tab">
            <li class="active">电视剧</li>
            <li>电影</li>
            <li>综艺</li>
        </ul>
        <div class="content">
            <div class="active">你是我的城池营垒</div>
            <div>我的姐姐</div>
            <div>怦然心动</div>
        </div>
    </div>
    <script>
        //获取所有li元素 div元素
        var tabList = document.querySelectorAll(".tabox .tab>li"),
            conList = document.querySelectorAll(".tabox .content>div");
        var prevIndex=0;
        for(var i=0;i<tabList.length;i++){
            var item=tabList[i];//获取当前每一项
            item.myIndex=i;//设置自定义属性
            item.onclick=function(){
                var curIndex=this.myIndex;
                //*** i不是当前点击这一项的索引,而是循环后的结果3[i&item都是全局的变量]
                //*** this:当前操作的这个LI
                //4.如果当前操作这一项和上一次选中的是相同项,则无需处理
                if(prevIndex===curIndex)return;
                //1.让当前操作的LI/DIV有选中样式
                tabList[curIndex].className=conList[curIndex].className='active';
                //2.让上一次选中的LI/DIV移除选中样式
                tabList[prevIndex].className=conList[prevIndex].className='';
                //3.让当前操作的这一项变为下一次操作的上一项
                prevIndex=curIndex;
            }
        }
    </script>
</body>
</html>

利用闭包的机制去解决【自执行函数】 推荐指数 **

<script>
         var tabList = document.querySelectorAll(".tabox .tab>li"),
             conList = document.querySelectorAll(".tabox .content>div");
            // 直接写“i”不行的原因:点击LI把绑定的函数执行,在形成的私有上下文中,遇到的变量“i”不是私有的,
            //而是其上级上下文「EC(G)全局」的;而此时全局的“i”,已经是循环最后的结果3...
        var prevIndex = 0;
        for (var i = 0; i < tabList.length; i++) {
            // 每一轮循环,执行一个自执行函数:有一个形参i,并且把当前这一轮循环全局i的值,传递给他
            //    第一轮循环  全局i=0   EC(AN1) 闭包1  私有i=0
            //    第二轮循环  全局i=1   EC(AN2) 闭包2  私有i=1
            //    第三轮循环  群居i=2   EC(AN3) 闭包3  私有i=2

          //之前i找到的上级上级是window 也就是GO,现在我们手动增加一层上下文,用一个闭包的形式,里面把点击事件赋值
                  //当点击页面上的元素的时候,就会找闭包作用域 EC(AN1) 中的私有变量i
            (function (i) {
                var item = tabList[i];
                item.onclick = function () {
                    if (i === prevIndex) return;
                    tabList[i].className = conList[i].className = 'active';
                    tabList[prevIndex].className = conList[prevIndex].className = '';
                    prevIndex = i;
                };
            })(i);
        } 
<script>

利用闭包的机制去解决【return函数】 推荐指数 **

每次for循环,就给li绑定一个点击事件,并且点击的事件的值是return里面的小函数,形成了不销毁的上下文 当我们点击li的时候,里面的小函数就会执行,变量i就是自执行函数里面的私有变量i

<script>
   var tabList = document.querySelectorAll(".tabox .tab>li"),
       conList = document.querySelectorAll(".tabox .content>div");
   var prevIndex = 0;
    for (var i = 0; i < tabList.length; i++) {
      var item = tabList[i];
      // 第一轮循环 全局i=0 闭包1 私有i=0
      // 第二轮循环 全局i=1 闭包2 私有i=1
      // ......
      item.onclick = (function (i) {
        return function () {
          if (i === prevIndex) return;
          tabList[i].className = conList[i].className = 'active';
          tabList[prevIndex].className = conList[prevIndex].className = '';
          prevIndex = i;
        };
      })(i);
    } 
<script>

利用闭包的机制去解决【forEach】 推荐指数 **

<script>   
        var tabList = document.querySelectorAll(".tabox .tab>li"),
        conList = document.querySelectorAll(".tabox .content>div");
        var prevIndex = 0;
        tabList.forEach(function (item, i) {
            // 第一轮循环 闭包 i=0
            // 第二轮循环 闭包 i=1
            // ....
            item.onclick = function () { 
                // i不是私有的,上级上下文是 第N个闭包... 用到的i也是这个闭包中存储的那个索引
                if (i === prevIndex) return;
                tabList[i].className = conList[i].className = 'active';
                tabList[prevIndex].className = conList[prevIndex].className = '';
                prevIndex = i;
            };
        });

<script>

利用【let】去解决 推荐指数 *

let 出现在{}中会生成一个父级块级私有上下文和 每轮循环生成一个块级私有上下文

<script>
      var tabList = document.querySelectorAll(".tabox .tab>li"),
        conList = document.querySelectorAll(".tabox .content>div");
        let prevIndex = 0;
    for (let i = 0; i < tabList.length; i++) {
            let item = tabList[i];
            item.onclick = function () {
                if (i === prevIndex) return;
                tabList[i].className = conList[i].className = 'active';
                tabList[prevIndex].className = conList[prevIndex].className = '';
                prevIndex = i;
            };
     } 
</script>