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

Chrome扩展实现WhatsApp Web消息前缀:Emoji消息失效问题求助

WhatsApp Web扩展Emoji消息前缀失效问题排查与修复

问题背景

开发的Chrome扩展通过content.js给WhatsApp Web发送的消息添加指定名称前缀(格式如「Thiago:\nHi」),纯文本消息正常,但含Emoji的消息无法添加前缀。

核心失效原因

  1. keydown事件无法覆盖Emoji输入场景
    代码中第一个keydown监听仅捕获单个字符的输入,但Emoji常通过输入法候选框、表情面板插入,这类操作不会触发符合event.key.length === 1的keydown事件,导致字符收集逻辑失效(虽未直接影响前缀添加,但会干扰内容跟踪)。

  2. Contenteditable元素的HTML结构与纯文本处理冲突
    WhatsApp Web的编辑器会将Emoji包装在特定HTML节点(如<span>)中,而非纯文本。当前代码用editor.innerText获取内容会丢失HTML结构,再通过document.execCommand("insertHTML")插入纯文本前缀,会破坏编辑器原生格式,导致WhatsApp无法识别前缀或直接丢弃异常内容。

  3. 换行符匹配逻辑不稳定
    代码中用硬编码的\n匹配前缀后的换行,但contenteditable的innerText中换行可能为\r\n,或因Emoji的HTML结构导致换行位置偏移,使replace无法命中前缀,最终前缀未被正确替换或重复添加。

  4. 事件监听执行时机冲突
    给Enter键和发送按钮添加的监听,可能与WhatsApp原生发送逻辑的执行顺序冲突,导致前缀未完成插入就触发发送。

修复方案

方案1:适配编辑器原生HTML结构(推荐)

直接操作DOM节点,保留WhatsApp的格式逻辑,避免纯文本与HTML结构的冲突:

function addNameToMessage() {
  chrome.storage.local.get(["savedName"], function (result) {
    const savedName = result.savedName || "Nome Padrão";
    const editor = document.querySelector("#main div[contenteditable='true']");
    if (!editor) return;

    const sendMessage = () => {
      // 检查是否已存在前缀,避免重复添加
      const prefixExists = Array.from(editor.childNodes).some(node => 
        node.textContent?.includes(`*${savedName}:*`)
      );
      if (!prefixExists) {
        // 创建符合编辑器格式的前缀节点
        const prefixNode = document.createElement("span");
        prefixNode.textContent = `*${savedName}:*\n`;
        editor.insertBefore(prefixNode, editor.firstChild);
      }

      // 触发input事件,让WhatsApp识别内容更新
      const inputEvent = new Event("input", { bubbles: true, cancelable: true });
      editor.dispatchEvent(inputEvent);

      // 执行发送
      const sendButton = document.querySelector("span[data-icon='send']");
      sendButton?.click();
    };

    // 监听Enter键(排除组合键场景)
    editor.addEventListener("keydown", (event) => {
      if (event.key === "Enter" && !event.ctrlKey && !event.altKey && !event.metaKey) {
        event.preventDefault();
        event.stopImmediatePropagation();
        sendMessage();
      }
    }, true);

    // 监听发送按钮点击,优先执行自定义逻辑
    const sendButton = document.querySelector("span[data-icon='send']");
    sendButton?.addEventListener("click", (event) => {
      event.preventDefault();
      event.stopImmediatePropagation();
      sendMessage();
    }, true);
  });
}

function waitForMainElement() {
  const mainElement = document.querySelector("#main");
  if (mainElement) {
    const editor = document.querySelector("#main div[contenteditable='true']");
    if (editor) {
      addNameToMessage();
      return; // 找到元素后停止轮询
    }
  }
  setTimeout(waitForMainElement, 1000);
}

waitForMainElement();

方案2:优化纯文本处理逻辑

若坚持用纯文本处理,需修复换行匹配并使用insertText避免HTML冲突:

// 修改sendMessage中的核心逻辑
const sendMessage = () => {
  const prefixRegex = new RegExp(`\\*${savedName}:\\*\\s*`, "g");
  const userMessage = editor.innerText.replace(prefixRegex, "").trim();
  const newMessage = `*${savedName}:*\n${userMessage}`;

  editor.focus();
  const range = document.createRange();
  range.selectNodeContents(editor);
  const selection = window.getSelection();
  selection.removeAllRanges();
  selection.addRange(range);
  
  // 用insertText代替insertHTML,自动适配编辑器格式
  document.execCommand("insertText", false, newMessage);

  const inputEvent = new Event("input", { bubbles: true });
  editor.dispatchEvent(inputEvent);

  const sendButton = document.querySelector("span[data-icon='send']");
  sendButton?.click();
};

关键修复说明

  • 使用insertText替代insertHTML:纯文本插入方式自动适配contenteditable原生格式,不会破坏Emoji的结构;
  • 正则匹配前缀:用\\s*匹配前缀后的任意空白字符(含各种换行符),确保替换逻辑稳定;
  • 前缀重复检查:发送前验证是否已添加前缀,避免重复插入;
  • 事件优先级控制:通过捕获阶段监听(第三个参数true)优先执行自定义逻辑,阻止原生事件冲突。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 05:44:56