掘金 人工智能 04月29日 14:02
编辑器、代码块、大模型AI对话中代码复制功能实现
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文深入探讨了如何使用现代浏览器原生Clipboard API实现代码块复制功能,并针对旧版浏览器和非HTTPS环境提供了兼容性解决方案。文章详细讲解了状态管理、样式定位以及内容处理的关键点,展示了如何通过代码实现复制功能,并提供了详细的代码示例和关键思路,帮助开发者更好地理解和应用Clipboard API。

✨**现代浏览器方案**:利用`navigator.clipboard.writeText()`实现复制功能,但需在HTTPS环境或localhost下使用,同时需要window.isSecureContext检测HTTPS本地环境。

🛠️**旧浏览器兼容方案**:针对不支持Clipboard API的浏览器,采用`document.execCommand('copy')`,创建临时的textarea元素,并将文本放入其中进行复制,确保在各种环境下都能实现复制功能。

💡**关键思路**:通过环境检测,优先使用现代API,降级使用旧方法。创建临时textarea元素是为了避免界面干扰,并确保文本可以被正确选中,同时处理了相关的用户体验问题,如提示信息和样式调整。

一、效果图

二、navigator.clipboard API

直奔主题。代码块复制使用现代浏览器原生 Clipboard API

  const [copied, setCopied] = useState(false);      // 处理复制逻辑      const handleCopy = async (code: string) => {        try {          await navigator.clipboard.writeText(code);          setCopied(true);          setTimeout(() => setCopied(false), 2000);        } catch (err) {          console.error('复制失败:', err);        }      };     const codeContent = String(children).replace(/\n$/, '')     return(      <button              onClick={() => handleCopy(codeContent)}              style={{                position: 'absolute',                right: 8,                top: 8,                padding: '4px 8px',                background: '#f5f5f5',                border: '1px solid #ddd',                borderRadius: 4,                cursor: 'pointer',                zIndex: 1,                opacity: copied ? 1 : 0.6,                 transition: "opacity 0.2s",              }}            >              {copied ? '复制成功' : '⎘ 复制'}           </button>     )

关键点说明

    状态管理:

使用 useState 跟踪复制状态,提供视觉反馈

2秒后自动重置复制状态提示

    样式定位

绝对定位到代码块右上角

使用:

 <div style={{position: 'relative'}}>//外层相对定位 //复制  {children && handCopyRender(children)}//复制块绝对定位 //代码块dom //例:<SyntaxHighlighter/> </div>
    内容处理:
const codeContent = String(children).replace(/\n$/, "");

移除代码结尾的多余换行符确保复制内容格式正确

三、浏览器兼容处理

    旧版浏览器不支持 Clipboard APIHTTP环境下无法生效浏览器安全限制:Clipboard API 要确保在 HTTPS 环境或 localhost 下使用

兼容性处理后:

const handCopyRender = (value: React.ReactNode) => {  /** 复制功能组件 */  const [copied, setCopied] = useState(false);    // 兼容性复制方法  const copyToClipboard = (text: string) => {    return new Promise<boolean>((resolve) => {      try {        // 现代浏览器方案        if (navigator.clipboard && window.isSecureContext) {          navigator.clipboard.writeText(text)            .then(() => resolve(true))            .catch(() => resolve(false));        }         // 旧浏览器兼容方案        else {          // 创建临时文本域          const textArea = document.createElement('textarea');          textArea.value = text;          textArea.style.position = 'fixed';  // 避免滚动跳转          textArea.style.opacity = '0';        // 透明不可见                    document.body.appendChild(textArea);          textArea.focus();//文本处于可编辑区域          textArea.select();//且被选中          // 执行复制命令          const success = document.execCommand('copy');          document.body.removeChild(textArea);          resolve(success);        }      } catch (err) {        console.error("复制失败:", err);        resolve(false);      }    });  };  const handleCopy = async () => {    try {      // 转换内容为字符串      const codeContent = String(value).replace(/\n$/, "");            // 执行复制操作      const success = await copyToClipboard(codeContent);            if (success) {        setCopied(true);        setTimeout(() => setCopied(false), 2000);      } else {        // 降级提示        alert("自动复制失败,请手动选择文本后按 Ctrl+C");      }    } catch (err) {      console.error("复制异常:", err);    }  };  return (    <button              onClick={handleCopy}              style={{                position: 'absolute',                right: 8,                top: 8,                padding: '4px 8px',                background: '#f5f5f5',                border: '1px solid #ddd',                borderRadius: 4,                cursor: 'pointer',                zIndex: 1,                opacity: copied ? 1 : 0.6,                transition: "opacity 0.2s",              }}            >              {copied ? '复制成功' : '⎘ 复制'}           </button>  );};

关键点说明

window.isSecureContext // 检测 HTTPS本地环境

window.isSecureContext是一个浏览器 API,用于检查当前页面是否在安全上下文中运行。如果页面在安全上下文中运行(即通过HTTPS加载),则该函数返回true,否则返回false。

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

Clipboard API 代码复制 浏览器兼容性
相关文章