如何用按钮ID动态检查localStorage并持久化折叠菜单状态?
折叠菜单状态统一存储与恢复方案
问题背景
我在侧边导航菜单中有30多个可折叠面板,每个触发按钮都带有唯一ID。点击按钮时需要用该按钮ID检查localStorage中是否存在对应键:
- 若存在对应键,则更新其值为菜单的展开/折叠状态(true/false);
- 若不存在对应键,则新增以该按钮ID为键、菜单状态为值的条目。
希望实现动态存储逻辑,无需为每个面板编写单独判断,后续增减面板也无需修改代码,同时能在页面加载时通过MutationObserver读取存储的状态,自动恢复面板的展开/折叠状态。
目前已能实现单个键值对的存储,但无法将所有面板状态存入同一个对象中,相关代码如下:
原始HTML代码
<a href="#" class="rpLink rpExpandable rpExpanded" id="button-id-one">Menu Button One</a> <a href="#" class="rpLink rpExpandable" id="button-id-two">Menu Button Two</a> <a href="#" class="rpLink rpExpandable" id="button-id-three">Menu Button Three</a>
原始点击监听JS代码
$(document).on("click",".rpExpandable",function() { var panelId = $(this).attr("id"); var panelState = false; if($(this).hasClass("rpExpanded")){panelState = true;} //update left menu panel settings in local storage persistLeftMenuPreferences(panelId,panelState); });
原始存储逻辑JS代码
function persistLeftMenuPreferences(panelId,panelState) { setTimeout(function() { //set item values in local storage localStorage.setItem(panelId, panelState); Cookies.set(panelId, panelState, {expires: 360}); }, 200); }
解决方案
将所有面板状态存入一个统一的对象,通过单个localStorage键存储该对象的JSON字符串,实现集中管理,同时适配动态面板的状态恢复。
1. 改造存储逻辑
更新persistLeftMenuPreferences函数,实现统一对象存储:
function persistLeftMenuPreferences(panelId, panelState) { setTimeout(function() { // 读取已存储的菜单状态对象,无数据则初始化空对象 let menuStates = JSON.parse(localStorage.getItem('leftMenuPanelStates')) || {}; // 更新当前面板的状态 menuStates[panelId] = panelState; // 序列化后存回localStorage localStorage.setItem('leftMenuPanelStates', JSON.stringify(menuStates)); // Cookie同步存储(同样用JSON字符串) Cookies.set('leftMenuPanelStates', JSON.stringify(menuStates), {expires: 360}); }, 200); }
2. 页面加载时恢复初始状态
页面就绪后,读取存储的状态并同步到DOM:
$(document).ready(function() { // 获取存储的菜单状态 let savedStates = JSON.parse(localStorage.getItem('leftMenuPanelStates')) || {}; // 遍历所有可折叠面板,恢复状态 $('.rpExpandable').each(function() { let panelId = $(this).attr('id'); if (savedStates.hasOwnProperty(panelId)) { savedStates[panelId] ? $(this).addClass('rpExpanded') : $(this).removeClass('rpExpanded'); } }); });
3. MutationObserver监听动态面板
若面板为动态生成(如异步加载),用MutationObserver监听DOM变化,自动恢复新面板状态:
// 初始化观察者 const menuObserver = new MutationObserver(function(mutations) { mutations.forEach(mutation => { // 检查新增节点中的可折叠面板 $(mutation.addedNodes).find('.rpExpandable').addBack('.rpExpandable').each(function() { const panelId = $(this).attr('id'); if (!panelId) return; const savedStates = JSON.parse(localStorage.getItem('leftMenuPanelStates')) || {}; if (savedStates.hasOwnProperty(panelId)) { savedStates[panelId] ? $(this).addClass('rpExpanded') : $(this).removeClass('rpExpanded'); } }); }); }); // 监听侧边菜单容器的DOM变化(替换为你的实际菜单容器选择器) menuObserver.observe(document.querySelector('#your-sidebar-container'), { childList: true, subtree: true });
4. 修正点击事件的状态判断
原点击事件的状态判断逻辑需要匹配实际切换行为,确保存储的是切换后的状态:
$(document).on("click", ".rpExpandable", function() { const $btn = $(this); const panelId = $btn.attr("id"); // 切换后的状态为当前类名的反值 const panelState = !$btn.hasClass("rpExpanded"); // 切换DOM类名(若原有逻辑未自动处理) $btn.toggleClass("rpExpanded"); // 存储状态 persistLeftMenuPreferences(panelId, panelState); });
内容的提问来源于stack exchange,提问作者Nic84
相关产品推荐
相关产品推荐

