使用Vanilla JS保存CSS手风琴菜单状态(无jQuery)
Hey there! Great question—you absolutely can save your accordion menu's expanded state across page reloads using vanilla JS and the browser's localStorage API. Your current setup uses the :target pseudo-class, which resets when the page reloads because the URL fragment doesn't persist (or changes) when navigating away. Let's fix that with a few simple tweaks.
Step 1: Update Your CSS
First, we'll add a custom class (expanded) to handle the expanded state alongside your existing :target functionality. This lets JS control the state while keeping your current click behavior intact:
.nav_bar { font-family: sans-serif; font-size: 20px; width: 250px; height: 100vh; position: fixed; top: 0px; left: 0px; } .nav_bar .nav_header { text-align: center; margin: 0; padding: 0; } .nav_bar .nav_header .nav_logo { width: 180px; } .nav_bar .menu { margin: 20px; overflow: hidden; } .nav_bar .menu .item { display: block; margin: 20px; position: relative; } .nav_bar .menu .item .sub_menu { overflow: hidden; -webkit-transition: 0.3s; transition: 0.3s; max-height: 0; } .nav_bar .menu .item .sub_menu a::before { content: ''; width: 2px; background: #280F98; position: absolute; top: 0; left: 0; height: 100%; } .nav_bar .menu .item .sub_menu a { display: block; font-size: 14px; padding: 10px 5px 10px 10px; position: relative; } /* Add this line to support both :target and JS-controlled expanded state */ .nav_bar .menu .item:target .sub_menu, .nav_bar .menu .item.expanded .sub_menu { max-height: 10em; }
Step 2: Add the Vanilla JavaScript
This code will:
- Save the expanded menu item's ID to
localStoragewhen it's opened - Load the saved state when the page reloads
- Handle submenu clicks to preserve the parent menu state before navigation
Add this script right before your closing </body> tag:
document.addEventListener('DOMContentLoaded', function() { const menuItems = document.querySelectorAll('.nav_bar .menu .item'); const menuButtons = document.querySelectorAll('.nav_bar .menu .item .button'); const subMenuLinks = document.querySelectorAll('.nav_bar .menu .item .sub_menu a'); // Load saved state on page load const savedExpandedId = localStorage.getItem('expandedMenuId'); if (savedExpandedId) { const savedItem = document.getElementById(savedExpandedId); if (savedItem) { savedItem.classList.add('expanded'); } } // Handle menu button clicks (toggle expand/collapse) menuButtons.forEach(button => { button.addEventListener('click', function(e) { const parentItem = this.closest('.item'); const isExpanded = parentItem.classList.contains('expanded'); // Collapse all other items menuItems.forEach(item => { if (item !== parentItem) { item.classList.remove('expanded'); } }); // Toggle current item if (isExpanded) { parentItem.classList.remove('expanded'); localStorage.removeItem('expandedMenuId'); } else { parentItem.classList.add('expanded'); localStorage.setItem('expandedMenuId', parentItem.id); } }); }); // Handle submenu link clicks (save state before navigation) subMenuLinks.forEach(link => { link.addEventListener('click', function() { const parentItem = this.closest('.item'); localStorage.setItem('expandedMenuId', parentItem.id); }); }); });
Step 3: How It Works
- LocalStorage: This browser feature lets us store small amounts of data (like the expanded menu ID) that persists even after the page is closed or reloaded.
- DOMContentLoaded: Ensures our JS runs only after the page's HTML is fully loaded.
- Menu Button Clicks: When you click a menu header, we toggle the
expandedclass and updatelocalStorageto reflect the current state. We also collapse any other open menus to keep the accordion behavior intact. - Submenu Links: When you click a submenu link, we save the parent menu's ID to
localStorageright before the page navigates away. When the new page loads, the script reads this ID and expands the correct menu.
Updated HTML (No Changes Needed!)
Your existing HTML works perfectly with this setup—no modifications required here:
<nav class="nav_bar"> <div class="menu"> <div class="item" id="our_work"> <a href="#our_work" class="button">Our Work</a> <div class="sub_menu"> <a href="our_work">Our mission</a> <a href="our_work#goals">Goals</a> <a href="our_work#initiatives">Initiatives</a> </div> </div> <div class="item" id="performances"> <a href="#performances" class="button">Showcase</a> <div class="sub_menu"> <a href="#">2020</a> <a href="#">2019</a> <a href="#">2018</a> <a href="#">2017</a> </div> </div> <div class="item" id="concerts"> <a href="#concerts" class="button">Talent</a> <div class="sub_menu"> <a href="#">Concerts 1</a> <a href="#">Concerts 2</a> <a href="#">Concerts 3</a> </div> </div> <div class="item" id="shop"> <a href="#shop" class="button">Shop</a> <div class="sub_menu"> <a href="#">Shop 1</a> <a href="#">Shop 2</a> <a href="#">Shop 3</a> </div> </div> </div> </nav>
This setup will keep your accordion menu expanded to the correct section every time the page reloads, whether you clicked the menu header or a submenu link.
内容的提问来源于stack exchange,提问作者amars

