StarFire_xm
  • 文章
  • 粉丝
  • 评论

浏览器复制文案功能兼容所有

2025-12-22 17:12:350 次浏览0 次评论技能类型: js
/**
 * 兼容所有浏览器的**到剪贴板函数(支持 Safari)
 * 支持 \n 换行符
 * @param {string} text - 要**的文本内容
 * @returns {Promise<void>}
 */
export const copyToClipboard = (text: string): Promise<void> => {
  return new Promise((resolve, reject) => {
    // 检测是否为 Safari 浏览器
    const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
    const isIOS = /ipad|iphone/i.test(navigator.userAgent);
   
    // Safari 浏览器(包括 iOS)直接使用降级方法,因为 navigator.clipboard 在 Safari 中限制较多
    if (isSafari || isIOS) {
      fallbackCopyToClipboard(text, resolve, reject);
      return;
    }
   
    // 其他浏览器优先使用现代 Clipboard API
    if (navigator.clipboard && navigator.clipboard.writeText) {
      navigator.clipboard
        .writeText(text)
        .then(() => resolve())
        .catch((error) => {
          // 如果 Clipboard API 失败,降级到传统方法
          console.warn('Clipboard API failed, falling back to execCommand:', error);
          fallbackCopyToClipboard(text, resolve, reject);
        });
    } else {
      // 降级到传统方法
      fallbackCopyToClipboard(text, resolve, reject);
    }
  });
};

/**
 * 降级**方法(兼容 Safari 旧版本)
 * @param {string} text - 要**的文本
 * @param {Function} resolve - Promise resolve
 * @param {Function} reject - Promise reject
 */
const fallbackCopyToClipboard = (
  text: string,
  resolve: () => void,
  reject: (error: Error) => void
) => {
  const isIOS = /ipad|iphone/i.test(navigator.userAgent);
 
  if (isIOS) {
    // iOS Safari 使用 contentEditable div 方法
    const div = document.createElement('div');
    div.contentEditable = 'true';
    div.innerHTML = text.replace(/\n/g, '<br>');
    div.style.position = 'fixed';
    div.style.top = '-9999px';
    div.style.left = '-9999px';
    div.style.width = '1px';
    div.style.height = '1px';
    div.style.opacity = '0';
    div.style.pointerEvents = 'none';
   
    document.body.appendChild(div);
   
    // 选择内容
    const range = document.createRange();
    range.selectNodeContents(div);
    const selection = window.getSelection();
    if (selection) {
      selection.removeAllRanges();
      selection.addRange(range);
    }
   
    setTimeout(() => {
      try {
        const successful = document.execCommand('copy');
        if (document.body.contains(div)) {
          document.body.removeChild(div);
        }
        if (selection) {
          selection.removeAllRanges();
        }
        if (successful) {
          resolve();
        } else {
          reject(new Error('execCommand copy failed on iOS'));
        }
      } catch (error) {
        if (document.body.contains(div)) {
          document.body.removeChild(div);
        }
        if (selection) {
          selection.removeAllRanges();
        }
        reject(error as Error);
      }
    }, 100);
  } else {
    // 桌面 Safari 和其他浏览器使用 textarea
    const textArea = document.createElement('textarea');
    textArea.value = text;
    textArea.readOnly = false;
   
    // 设置样式使其不可见但可**
    textArea.style.position = 'fixed';
    textArea.style.top = '0';
    textArea.style.left = '0';
    textArea.style.width = '1px';
    textArea.style.height = '1px';
    textArea.style.padding = '0';
    textArea.style.border = 'none';
    textArea.style.outline = 'none';
    textArea.style.boxShadow = 'none';
    textArea.style.background = 'transparent';
    textArea.style.opacity = '0';
    textArea.style.zIndex = '-9999';
    textArea.style.pointerEvents = 'none';
   
    // 添加到 DOM
    document.body.appendChild(textArea);
   
    // Safari 需要特殊处理
    const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
   
    if (isSafari) {
      // Safari 需要先设置 selectionRange,再 focus
      textArea.setSelectionRange(0, text.length);
      textArea.focus();
    } else {
      // 其他浏览器先 focus 再 select
      textArea.focus();
      textArea.select();
    }
   
    // 使用 setTimeout 确保选择操作完成(Safari 需要稍长的延迟)
    const delay = isSafari ? 10 : 0;
    setTimeout(() => {
      try {
        // 再次确保选择(Safari 有时需要)
        if (isSafari) {
          textArea.setSelectionRange(0, text.length);
        }
       
        // 执行**命令
        const successful = document.execCommand('copy');
       
        // 清理:移除临时元素
        if (document.body.contains(textArea)) {
          document.body.removeChild(textArea);
        }
       
        if (successful) {
          resolve();
        } else {
          reject(new Error('execCommand copy failed'));
        }
      } catch (error) {
        // 清理:移除临时元素
        if (document.body.contains(textArea)) {
          document.body.removeChild(textArea);
        }
        reject(error as Error);
      }
    }, delay);
  }
};


    发表

    还没有评论哦,来抢个沙发吧!