Phoenix框架侧边栏下拉菜单点击项后保持展开的实现
Phoenix + Tailwind + Flowbite 侧边栏下拉菜单点击后保持展开的解决方案
问题说明
我基于Phoenix框架构建应用,搭配Tailwind CSS和Flowbite组件库。侧边栏的下拉菜单在点击菜单项时会自动收起,用户体验不佳。尝试过使用Flowbite的ignoreClickOutsideClass选项但不清楚用法,自行编写的JavaScript代码也未达到预期效果,需求是点击下拉菜单项后菜单保持展开状态。
现有代码
HTML 结构
<button type="button" class="flex items-center w-full p-2 text-base text-gray-900 transition duration-75 rounded-lg group hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-gray-700" aria-controls="dropdown-layouts-router-api-config" data-collapse-toggle="dropdown-layouts-router-api-config" > <svg class="flex-shrink-0 w-6 h-6 text-gray-500 transition duration-75 group-hover:text-gray-900 dark:text-gray-400 dark:group-hover:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24" > <path fill-rule="evenodd" d="M12 8a1 1 0 0 0-1 1v10H9a1 1 0 1 0 0 2h11a1 1 0 0 0 1-1V9a1 1 0 0 0-1-1h-8Zm4 10a2 2 0 1 1 0-4 2 2 0 0 1 0 4Z" clip-rule="evenodd"/> <path fill-rule="evenodd" d="M5 3a2 2 0 0 0-2 2v6h6V9a3 3 0 0 1 3-3h8c.35 0 .687.06 1 .17V5a2 2 0 0 0-2-2H5Zm4 10H3v2a2 2 0 0 0 2 2h4v-4Z" clip-rule="evenodd"/> </svg> <span class="flex-1 ml-3 text-left whitespace-nowrap" sidebar-toggle-item> Routers </span> <svg sidebar-toggle-item class="w-6 h-6" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" > <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" > </path> </svg> </button> <ul id="dropdown-layouts-router-api-config" class="hidden py-2 space-y-2"> <li> <a href="/routers" class="flex items-center p-2 text-base text-gray-900 transition duration-75 rounded-lg pl-11 group hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-gray-700" > Router list </a> </li> </ul>
(注:将原Phoenix模板中的<.link>转为标准HTML的<a>标签)
尝试过的JavaScript代码
document.addEventListener("DOMContentLoaded", function () { const dropdownBtn = document.getElementById("dropdownBtn"); const dropdownMenu = document.getElementById("dropdownMenu"); const chevron = document.getElementById("chevron"); dropdownBtn.addEventListener("click", function (event) { event.stopPropagation(); // Prevent closing when clicking inside the dropdown dropdownMenu.classList.toggle("hidden"); chevron.classList.toggle("rotate-180"); }); // Prevent dropdown from closing when clicking on items document.querySelectorAll("#dropdownMenu a").forEach(item => { item.addEventListener("click", function (event) { event.stopPropagation(); // Stop event from bubbling up }); }); // Close dropdown if clicked outside document.addEventListener("click", function () { dropdownMenu.classList.add("hidden"); chevron.classList.remove("rotate-180"); }); });
解决方案
方法一:使用Flowbite原生配置(推荐)
Flowbite的折叠组件支持通过ignoreClickOutsideClass配置忽略特定元素的点击事件,具体步骤:
- 修改HTML结构:给下拉菜单容器和菜单项添加自定义类(比如
ignore-collapse-close)
<!-- 下拉菜单容器添加类 --> <ul id="dropdown-layouts-router-api-config" class="hidden py-2 space-y-2 ignore-collapse-close"> <li> <!-- 菜单项链接添加类 --> <a href="/routers" class="flex items-center p-2 text-base text-gray-900 transition duration-75 rounded-lg pl-11 group hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-gray-700 ignore-collapse-close" > Router list </a> </li> </ul>
- 初始化Flowbite时配置忽略类:
document.addEventListener('DOMContentLoaded', function() { window.Flowbite.initCollapse({ ignoreClickOutsideClass: 'ignore-collapse-close' }); });
这样点击带有ignore-collapse-close类的元素时,Flowbite不会触发折叠菜单的收起逻辑。
方法二:修正自定义JavaScript代码
原代码的问题在于元素ID不匹配(原HTML中没有dropdownBtn、dropdownMenu这些ID),同时需要避免与Flowbite的默认监听冲突,修改后代码:
document.addEventListener("DOMContentLoaded", function () { // 匹配实际HTML中的元素 const dropdownBtn = document.querySelector('[data-collapse-toggle="dropdown-layouts-router-api-config"]'); const dropdownMenu = document.getElementById("dropdown-layouts-router-api-config"); const chevron = dropdownBtn.querySelector('svg[sidebar-toggle-item]:last-child'); // 阻止Flowbite默认事件,接管折叠逻辑 dropdownBtn.addEventListener("click", function (event) { event.stopImmediatePropagation(); dropdownMenu.classList.toggle("hidden"); chevron.classList.toggle("rotate-180"); }); // 点击菜单项时阻止事件冒泡,避免触发外部收起逻辑 dropdownMenu.querySelectorAll("a").forEach(item => { item.addEventListener("click", function (event) { event.stopImmediatePropagation(); }); }); // 点击外部区域时收起菜单 document.addEventListener("click", function (event) { if (!dropdownBtn.contains(event.target) && !dropdownMenu.contains(event.target)) { dropdownMenu.classList.add("hidden"); chevron.classList.remove("rotate-180"); } }); });
注意:如果使用此方法,建议移除按钮上的data-collapse-toggle属性,避免与Flowbite的默认折叠逻辑冲突。
内容的提问来源于stack exchange,提问作者Mostafiz Ur Rahman
相关产品推荐
相关产品推荐

