Skip to content

弹窗点击位置定位技术实现解析

背景与效果

传统弹窗通常居中显示,但在以下场景存在体验问题:

  1. 操作链路过长时,用户视线需要频繁跳转
  2. 大屏场景下鼠标移动距离过远
  3. 移动端缺乏空间关联性

动态定位效果

  • 弹窗从点击位置附近弹出
  • 自动避让视口边界
  • 保持20px安全边距
  • 视觉动效跟随操作焦点

整体方案

实现分为四个关键阶段:

  1. 坐标捕获:全局事件捕获
  2. 定位计算:初始位置 + 边界检测
  3. 样式注入:动态修改定位样式
  4. 状态清理:弹窗关闭时重置坐标

实现步骤详解

1. 事件捕获阶段

typescript
// 全局坐标存储器
let lastClickPosition = { x: -1000, y: -1000 };

// 捕获阶段监听点击事件
document.addEventListener('click', (e: MouseEvent) => {
  lastClickPosition = {
    x: e.clientX,
    y: e.clientY
  };
}, true);

技术要点

  • 使用事件捕获阶段确保先于业务代码执行
  • clientX/clientY获取视口绝对坐标
  • 初始值设为屏幕外坐标作为异常保护

2. 弹窗初始化

tsx
function showConfirm() {
  const basePos = lastClickPosition;

  const modal = new Modal({
    style: {
      position: 'fixed',
      left: `${basePos.x}px`,
      top: `${basePos.y}px`,
      transform: 'translate(-50%, -50%)'
    }
  });

  // 边界检测
  setTimeout(() => {
    const rect = modal.element.getBoundingClientRect();
    const viewport = {
      width: window.innerWidth,
      height: window.innerHeight
    };

    if (rect.right > viewport.width - 20) {
      modal.element.style.left = `${viewport.width - rect.width - 20}px`;
    }
    if (rect.bottom > viewport.height - 20) {
      modal.element.style.top = `${viewport.height - rect.height - 20}px`;
    }
  }, 0);
}

3. 坐标清理

typescript
// 弹窗关闭时重置坐标
function closeModal() {
  lastClickPosition = { x: -1000, y: -1000 };
}