【问题标题】:JavaScript local storage mixing up toggle keys?JavaScript本地存储混淆了切换键?
【发布时间】:2021-09-15 22:00:12
【问题描述】:

我是一名 Javascript 初学者,尝试使用本地存储来存储一组按钮切换状态(开/关)。我的目标是能够在浏览器刷新后切换一组 svg 填充,打开和关闭,并存储状态,返回到选定状态。

//LOOP 1 - GET STORED VALUES AND SET SVGs ACCORDINGLY
        function grabStoredStates(){
              for (let i=0; i < localStorage.length; i++) {
                  let key = localStorage.key(i);
                  let value = localStorage.getItem(key);
                  if (value == "on") {
                      //"cbox" below is from LOOP 2  - maybe it's causing the problem
                  cbox[i].style.fill = "coral";
              }
          }
        }

//LOOP 2 - TOGGLE AND STORE TOGGLE STATES
         let cbox = document.querySelectorAll(".toggleMe");
         for (let i = 0; i < cbox.length; i++) {
                cbox[i].addEventListener("click", function() {
                   if (cbox[i].style.fill == "coral") {
                       cbox[i].style.fill = "white";
                       localStorage.setItem(cbox[i].id, "off");
                   }else{
                      cbox[i].style.fill = "coral";
                     localStorage.setItem(cbox[i].id, "on");

                   }
                });
            }
<body onload="grabStoredStates()">
    <svg height="300" width="700>
    <g  pointer-events="all">    
      <rect class="toggleMe" cursor:pointer; id="rect1" width="100" height="100" x="50" y="80" fill="aliceblue" stroke="black" stroke-width="2" />
      <rect class="toggleMe" cursor:pointer; id="rect2" width="100" height="100" x="175" y="80" fill="aliceblue" stroke="black" stroke-width="2" />
      <rect class="toggleMe" cursor:pointer; id="rect3" width="100" height="100" x="300" y="80" fill="aliceblue" stroke="black" stroke-width="2" />
      <rect class="toggleMe" cursor:pointer; id="rect4" width="100" height="100" x="425" y="80" fill="aliceblue" stroke="black" stroke-width="2" />
      </g>
    </svg>
</body>

我的问题是,如果您加载页面,然后在 Chrome 开发工具中打开本地存储,(应用程序 > 存储 > 本地存储),然后从左到右依次单击矩形,您应该会看到这一点,因为它们从浅蓝色正确切换到橙色:

关键值

rect1 开启

rect2 开启

rect3 开启

rect4 开启

在本地存储中,键和值在这一点上是正确匹配的,所有方块都显示为橙色,正如预期的那样。但是,如果您随后单击 rect3(左起第三个矩形),例如,将其切换为浅蓝色,并具有预期的相应“关闭”状态 - 在刷新页面时,存储的值似乎变得混乱,与循环显然对矩形重新编号,就好像它从 [0] 开始一样 - 忽略了预期的键/值对。然后你会看到:

键值[问题]

rect1 开启

rect2 on [ --> 显示为关闭]

rect3 off [ --> 显示为 on]

rect4 开启

有什么方法可以让键和值保持在一起,而不管调用循环。 “grabStoredStates()”循环似乎可以工作,通过手动更改值和刷新进行测试...我怀疑它与两个单独的 for 循环之间的转换有关?也许“cbox”循环也应该在一个函数中?我查看了先前的堆栈溢出“不能在本地存储中使用布尔值”的答案,但是当我使用“on”和“off”时,这似乎并不适用。我还看到了一个 jQuery 答案,但我还不熟悉那个库。 (但是,如果提供 jQuery 答案,我不会拒绝。)

同样,我最初的目标是能够打开和关闭 svg 填充,并在浏览器刷新后存储状态。如果有的话,我会喜欢一种更优雅的方式......

提前感谢大家的帮助。

【问题讨论】:

标签: javascript html for-loop svg local-storage


【解决方案1】:

在这里我尝试制​​作一个更简单的版本。 &lt;rect&gt;s 的表示依赖于一个名为 data-state 的属性。加载文档后,属性将被更新(我注释掉了 localStorage 的代码并将其替换为数组testArr)。 &lt;g&gt; 上的事件侦听器将处理单击事件并测试是否单击了 &lt;rect&gt;,如果是,则更新/切换属性。之后所有值都保存到 localStorage/testArr。

var cbox;
var testArr = ['on', 'off', 'off', 'on']; // for testing

document.addEventListener('DOMContentLoaded', e => {
  cbox = document.querySelectorAll(".toggleMe");
  /* // Code for localStorage:
  Array.from(Array(localStorage.length).keys()).forEach(i => {
    let key = localStorage.key(i);
    let value = localStorage.getItem(key);
    cbox[i].attributes['data-state'] = value;
  });*/
  testArr.forEach((state, i) => cbox[i].attributes['data-state'].value = state); // for testing
  
  document.querySelector('g').addEventListener('click', e => {
    if(e.target.classList.contains('toggleMe')){
      let currentValue = e.target.attributes['data-state'].value;
      e.target.attributes['data-state'].value = (currentValue == 'on') ? 'off' : 'on';
      /* // Code for localStorage:
      [...cbox].forEach((elm, i) => {
        let value = elm.attributes['data-state'].value;
        localStorage.setItem(`Rect${i}`, value);
      });*/
      
      testArr = [...cbox].map(elm => elm.attributes['data-state'].value); // for testing
      console.log(testArr.join(',')); // for testing
    }
  });
});
rect.toggleMe {
  cursor: pointer;
  width: 50px;
  height: 50px;
  stroke: black;
  stroke-width: 2px;
}

rect[data-state="on"] {
  fill: aliceblue;
}

rect[data-state="off"] {
  fill: coral;
}
<body>
  <svg height="300" width="300">
    <g>    
      <rect class="toggleMe" data-state="off" x="50" y="80" />
      <rect class="toggleMe" data-state="off" x="110" y="80" />
      <rect class="toggleMe" data-state="off" x="170" y="80" />
      <rect class="toggleMe" data-state="off" x="230" y="80" />
    </g>
  </svg>
</body>

【讨论】:

  • Chrwahl,感谢您的及时帮助。我认识到这似乎是一个优雅的解决方案——一些功能超出了我的能力范围,我渴望学习——但我在检索值时遇到了实现问题(localStorage.getItem 部分)。我将代码加载到我的 Chrome 浏览器中,注释掉四个“用于测试”行并运行它。我可以让它将项目存储到本地存储中,但是在刷新时,方块都会恢复到原来的橙色设置——但本地存储是正确的。难道我做错了什么?再次感谢。我知道你一定很忙……
  • 忘了提一下,打印到控制台的测试数组运行良好。也许我可以以某种方式将其存储在本地存储中?
  • @SultanaSmock 预期和本地存储之间可能不匹配。尝试加载页面,清除 localStorage (localStorage.clear()),然后单击其中一个按钮(然后重新加载)。但正如您所建议的,为什么不直接将数组存储在 localStorage 中。我个人会去的。在存储/加载数组时执行localStorage.setItem("something", JSON.stringify(testArr))testArr = JSON.parse(localStorage.getItem("something")) 之类的操作。
  • chrwahl,对不起,我离开了这么久。感谢您再次入住。我也会看看这种新方法......
猜你喜欢
  • 1970-01-01
  • 2012-12-24
  • 1970-01-01
  • 1970-01-01
  • 2018-10-28
  • 2013-09-12
  • 1970-01-01
  • 2021-07-19
  • 1970-01-01
相关资源
最近更新 更多