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

如何实现屏蔽除滚动外的所有鼠标事件?

解决加载遮罩屏蔽交互同时保留滚动的方案

核心思路

给遮罩设置pointer-events: none让滚动事件穿透到下方元素,同时通过window层面的事件捕获,判断点击/触摸等交互的目标是否处于遮罩覆盖范围内,若在范围内则阻止事件触发,实现「屏蔽交互+保留滚动」的效果。

具体实现

1. 遮罩基础样式

保持遮罩的定位、半透明和加载动画,关键设置pointer-events: none允许滚动穿透:

.loading-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(255,255,255,0.7);
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none; /* 核心:允许滚动事件穿透 */
  z-index: 999;
}

/* 可选:加载动画样式 */
.loading-spinner {
  width: 40px;
  height: 40px;
  border: 4px solid #ccc;
  border-top-color: #333;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

2. Window层面的事件拦截

通过事件捕获机制,在window上监听需要屏蔽的交互事件,判断目标元素是否被遮罩覆盖,是则阻止事件:

// 初始化遮罩(通用组件化写法)
class LoadingOverlay {
  constructor() {
    this.overlay = this.createOverlay();
    this.eventHandlers = [];
    this.bindBlockEvents();
  }

  // 创建遮罩DOM
  createOverlay() {
    const overlay = document.createElement('div');
    overlay.className = 'loading-overlay';
    const spinner = document.createElement('div');
    spinner.className = 'loading-spinner';
    overlay.appendChild(spinner);
    return overlay;
  }

  // 显示遮罩,可指定目标容器
  show(target = document.body) {
    target.style.position = 'relative'; // 确保遮罩相对目标定位
    target.appendChild(this.overlay);
  }

  // 隐藏遮罩
  hide() {
    this.overlay.remove();
  }

  // 绑定需要拦截的事件
  bindBlockEvents() {
    const blockEventTypes = ['click', 'mousedown', 'touchstart', 'keydown'];
    
    blockEventTypes.forEach(type => {
      const handler = (e) => {
        let target = e.target;
        // 向上遍历DOM,检查目标是否被遮罩覆盖
        while (target && target !== document.body) {
          const targetRect = target.getBoundingClientRect();
          const overlayRect = this.overlay.getBoundingClientRect();
          // 判断元素是否在遮罩范围内
          const isCovered = 
            targetRect.top < overlayRect.bottom &&
            targetRect.bottom > overlayRect.top &&
            targetRect.left < overlayRect.right &&
            targetRect.right > overlayRect.left;

          if (isCovered) {
            e.stopPropagation();
            e.preventDefault();
            return;
          }
          target = target.parentNode;
        }
      };
      // 捕获阶段触发,确保先于元素自身事件处理
      window.addEventListener(type, handler, true);
      this.eventHandlers.push({ type, handler });
    });
  }

  // 移除事件监听,避免内存泄漏
  unbindBlockEvents() {
    this.eventHandlers.forEach(({ type, handler }) => {
      window.removeEventListener(type, handler, true);
    });
    this.eventHandlers = [];
  }

  // 销毁组件
  destroy() {
    this.hide();
    this.unbindBlockEvents();
  }
}

3. 使用示例

// 创建遮罩实例
const loadingMask = new LoadingOverlay();
// 在指定容器上显示遮罩
const targetContainer = document.getElementById('scrollable-div');
loadingMask.show(targetContainer);

// 加载完成后隐藏/销毁
// loadingMask.hide();
// loadingMask.destroy();

方案优势

  • 完全适配需求:无需了解下方内容结构或滚动元素数量,遮罩直接放目标上方即可
  • 改动极小:不需要修改原有业务代码,仅引入通用组件
  • 基于window层面处理:通过事件捕获统一拦截交互,不侵入业务逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 04:30:15