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

如何在Chrome扩展中临时禁用Bootstrap模态框的enforceFocus属性

解决方案:解决Chrome扩展弹窗焦点被Bootstrap模态框抢占及Shadow DOM样式丢失问题

一、临时禁用Bootstrap模态框的enforceFocus

可以通过Chrome扩展的内容脚本实现临时修改,核心思路是在扩展弹窗打开时记录目标网站模态框的原始配置,关闭时恢复。

代码实现

// 保存原始enforceFocus状态的数组
let originalEnforceFocusStates = [];

// 打开扩展弹窗时执行
function openExtensionModal() {
  // 定位当前页面所有处于激活状态的Bootstrap模态框
  const activeModals = document.querySelectorAll('.modal.in, .modal.show');
  
  activeModals.forEach(modalEl => {
    // 获取模态框实例(兼容Bootstrap 3/4/5)
    const modalInstance = window.$?.fn.modal.getInstance 
      ? window.$.fn.modal.getInstance(modalEl) 
      : modalEl.modal;

    if (modalInstance) {
      // 保存原始配置值
      const originalValue = modalInstance.options?.enforceFocus ?? true;
      originalEnforceFocusStates.push({
        instance: modalInstance,
        originalValue
      });

      // 临时禁用enforceFocus
      if (modalInstance.options) {
        modalInstance.options.enforceFocus = false;
      }
      // 针对Bootstrap 3的特殊处理:若实例未自定义enforceFocus,需手动添加属性覆盖全局默认
      if (window.$?.fn.modal.Constructor && !modalInstance.options.hasOwnProperty('enforceFocus')) {
        modalInstance.options.enforceFocus = false;
      }
    }
  });

  // 此处添加你的扩展弹窗DOM注入逻辑...
}

// 关闭扩展弹窗时执行
function closeExtensionModal() {
  // 恢复每个模态框的原始配置
  originalEnforceFocusStates.forEach(({ instance, originalValue }) => {
    if (instance.options) {
      instance.options.enforceFocus = originalValue;
      // Bootstrap 3场景:若之前是临时添加的属性,删除后恢复全局默认
      if (window.$?.fn.modal.Constructor && !instance.options.hasOwnProperty('enforceFocus')) {
        delete instance.options.enforceFocus;
      }
    }
  });
  originalEnforceFocusStates = [];

  // 此处添加你的扩展弹窗DOM移除逻辑...
}

二、使用Shadow DOM解决焦点问题并保留样式

Shadow DOM的样式隔离特性可以彻底规避外部Bootstrap的焦点抢占,同时需要将弹窗样式注入到Shadow根内部以避免丢失。

代码实现

function createExtensionModal() {
  // 创建弹窗容器
  const modalContainer = document.createElement('div');
  // 附加Shadow根(open模式方便调试,close模式更彻底隔离)
  const shadowRoot = modalContainer.attachShadow({ mode: 'open' });

  // 弹窗HTML结构
  const modalHTML = `
    <div class="extension-modal">
      <div class="modal-inner">
        <textarea placeholder="输入内容..."></textarea>
        <button id="modal-close">关闭</button>
      </div>
    </div>
  `;

  // 弹窗内联样式(也可从扩展内部CSS文件读取内容)
  const modalCSS = `
    .extension-modal {
      position: fixed;
      top: 0;
      left: 0;
      width: 100vw;
      height: 100vh;
      background-color: rgba(0, 0, 0, 0.6);
      display: flex;
      align-items: center;
      justify-content: center;
      z-index: 999999;
    }
    .modal-inner {
      background: #fff;
      padding: 24px;
      border-radius: 8px;
      width: 420px;
      box-shadow: 0 4px 12px rgba(0,0,0,0.15);
    }
    textarea {
      width: 100%;
      height: 120px;
      padding: 10px;
      box-sizing: border-box;
      border: 1px solid #ddd;
      border-radius: 4px;
      margin-bottom: 16px;
    }
    #modal-close {
      padding: 8px 16px;
      background-color: #007bff;
      color: #fff;
      border: none;
      border-radius: 4px;
      cursor: pointer;
    }
    #modal-close:hover {
      background-color: #0056b3;
    }
  `;

  // 注入样式到Shadow根
  const styleEl = document.createElement('style');
  styleEl.textContent = modalCSS;
  shadowRoot.appendChild(styleEl);

  // 注入弹窗HTML到Shadow根
  shadowRoot.innerHTML += modalHTML;

  // 添加关闭事件
  const closeBtn = shadowRoot.getElementById('modal-close');
  closeBtn.addEventListener('click', () => {
    document.body.removeChild(modalContainer);
  });

  // 将容器添加到页面
  document.body.appendChild(modalContainer);

  // 自动聚焦textarea
  const textarea = shadowRoot.querySelector('textarea');
  textarea.focus();
}

补充:加载外部CSS到Shadow根

如果你的弹窗样式写在单独的CSS文件中,可以通过fetch读取内容后注入:

async function loadExtensionCSS(shadowRoot, cssPath) {
  const cssUrl = chrome.runtime.getURL(cssPath);
  const response = await fetch(cssUrl);
  const cssText = await response.text();
  
  const styleEl = document.createElement('style');
  styleEl.textContent = cssText;
  shadowRoot.appendChild(styleEl);
}

// 使用示例:
// loadExtensionCSS(shadowRoot, 'styles/modal.css');

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 19:47:42