You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现下拉菜单打开时禁用页面滚动并支持动态扩展?

可扩展的导航栏下拉菜单滚动控制方案

核心思路

放弃固定ID监听,改用统一类名标识下拉菜单,结合动态元素监听或状态计数的方式,实现新增下拉菜单无需修改脚本的效果。以下是两种可行方案:


方案一:基于MutationObserver的动态监听(适配Webflow默认类)

利用父元素监听自动捕获新增的下拉菜单,统一检查所有下拉的状态:

// 替换为你的导航栏父元素选择器(比如Webflow的导航栏容器类)
const navbarContainer = document.querySelector('.navbar');

// 统一检查所有下拉菜单的打开状态
function checkDropdownState() {
  // 选择所有带统一类名的下拉元素(这里用dropdown-trigger作为示例,可自定义)
  const hasOpenDropdown = [...document.querySelectorAll('.dropdown-trigger')].some(el => el.classList.contains('w--open'));
  // 用auto替代visible,更符合页面默认滚动行为
  document.body.style.overflow = hasOpenDropdown ? 'hidden' : 'auto';
}

// 为单个下拉元素创建类名观察者
const createDropdownObserver = (element) => {
  const observer = new MutationObserver(mutations => {
    mutations.forEach(mutation => {
      if (mutation.attributeName === 'class') {
        checkDropdownState();
      }
    });
  });
  observer.observe(element, { attributes: true, attributeFilter: ['class'] });
  return observer;
};

// 初始化现有下拉菜单的观察者
document.querySelectorAll('.dropdown-trigger').forEach(el => createDropdownObserver(el));

// 监听导航栏父元素,自动给新增的下拉菜单绑定观察者
const parentObserver = new MutationObserver(mutations => {
  mutations.forEach(mutation => {
    mutation.addedNodes.forEach(node => {
      if (node.nodeType === 1 && node.classList.contains('dropdown-trigger')) {
        createDropdownObserver(node);
      }
    });
  });
});

parentObserver.observe(navbarContainer, { childList: true, subtree: true });

方案优势

  1. 新增下拉菜单时,只要给元素添加dropdown-trigger类,脚本自动监听,无需修改代码
  2. 基于Webflow原生的w--open类做判断,无需额外修改框架逻辑

方案二:事件委托+状态计数(性能更优)

通过计数跟踪打开的下拉菜单数量,避免每次遍历所有元素:

let openDropdownCount = 0;

// 更新页面滚动状态
function updateScrollState() {
  document.body.style.overflow = openDropdownCount > 0 ? 'hidden' : 'auto';
}

// 事件委托监听导航栏内的点击(适配Webflow下拉触发逻辑)
document.querySelector('.navbar').addEventListener('click', (e) => {
  const dropdown = e.target.closest('.dropdown-trigger');
  if (!dropdown) return;

  const wasOpen = dropdown.classList.contains('w--open');
  dropdown.classList.toggle('w--open');
  
  // 同步更新计数
  openDropdownCount += wasOpen ? -1 : 1;
  updateScrollState();
});

// 补充监听非点击触发的状态变化(比如键盘操作)
const classObserver = new MutationObserver(mutations => {
  mutations.forEach(mutation => {
    if (mutation.attributeName === 'class') {
      const el = mutation.target;
      const isNowOpen = el.classList.contains('w--open');
      const wasPreviouslyOpen = mutation.oldValue?.includes('w--open') ?? false;
      
      if (isNowOpen !== wasPreviouslyOpen) {
        openDropdownCount += isNowOpen ? 1 : -1;
        updateScrollState();
      }
    }
  });
});

// 初始化现有下拉菜单的类监听
document.querySelectorAll('.dropdown-trigger').forEach(el => {
  classObserver.observe(el, { attributes: true, attributeFilter: ['class'], attributeOldValue: true });
});

// 自动监听新增的下拉菜单
document.querySelector('.navbar').addEventListener('DOMNodeInserted', (e) => {
  if (e.target.classList?.contains('dropdown-trigger')) {
    classObserver.observe(e.target, { attributes: true, attributeFilter: ['class'], attributeOldValue: true });
  }
});

方案优势

  1. 通过计数替代全量遍历,性能更高效
  2. 同时覆盖点击和非点击触发的状态变化,避免滚动异常
  3. 同样支持动态新增下拉菜单,无需修改脚本

注意事项

  1. 确保所有下拉菜单(包括未来新增的)都添加统一的标识类(比如示例中的dropdown-trigger)
  2. 恢复滚动时推荐用auto而非visible,避免布局异常
  3. 如果使用Webflow,可直接在元素的类设置中批量添加统一类名

内容的提问来源于stack exchange,提问作者Sam Garcia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 12:01:33