普通视图

发现新文章,点击刷新页面。
今天 — 2025年12月4日首页

从零实现一个“类微信”表情输入组件

作者 streaker303
2025年12月4日 15:06

📋 背景

最近接到一个需求:在系统中添加表情输入功能。由于需要与腾讯某平台保持数据一致,表情包的数量和取值都要完全相同。

翻阅文档后发现并没有提供现成组件,只能自己实现。

先观察了实现方式:打开控制台面板,点击表情后会瞬间请求大量图片。

输入逻辑上,用户选择 😊 后值自动变成 [微笑],用户直接输入 [微笑] 也能映射成对应表情图片。

🚩 最终目标

  • ✅ 支持点击表情面板插入表情
  • ✅ 支持输入 [微笑] 自动转换为表情图片
  • ✅ 完成双向绑定,取值时图片转回 [微笑] 文本
  • ✅ 字符长度计算:中文 1 个字符,英文 0.5 个,表情 1 个
  • ✅ 光标定位准确,体验流畅
  • ✅ 输入法友好,不在拼音输入阶段转换

🧩 实现步骤

1、获取表情包数据

最初尝试在网上找表情包资源,但数量总是对不上。近百个表情包如果手动逐个校对太过折磨,于是尝试从页面爬取数据。 在浏览器控制台执行以下脚本:

// 获取所有表情元素
const emojiItems = document.querySelectorAll('.emoji-list li');

// 提取关键信息:图片地址、文本代码、文件名
const emojiArray = Array.from(emojiItems).map(li => {
  const img = li.querySelector('img');
  return img ? {
    src: img.src,
    alt: img.alt,
    dataImage: img.getAttribute('data-image')
  } : null;
}). filter(Boolean);

console.log(emojiArray);

执行后直接在控制台复制数组,保存为 JSON 文件。

src 只做下载使用,alt 需要用来做映射,dataImage 用于拼接读取表情图片路径。

[  {    "alt": "[微笑]",    "src": "https://xxx.qq.com/xxx/emojis/smiley_0.png"    "dataImage": "smiley_0"  }]

2、批量下载图片

使用 Node. js 脚本批量下载表情图片:

const fs = require('fs');
const path = require('path');

const outputDir = path. resolve(__dirname, 'emojis');
if (!fs.existsSync(outputDir)) {
  fs.mkdirSync(outputDir, { recursive: true });
}

async function downloadImage(item) {
  const fileName = `${item.dataImage || item.alt || 'emoji'}. png`;
  const filePath = path.join(outputDir, fileName);
  
  try {
    const res = await fetch(item.src);
    if (!res.ok) throw new Error(`Failed to fetch ${item.src}`);
    
    const buffer = await res.arrayBuffer();
    fs.writeFileSync(filePath, Buffer.from(buffer));
    console.log(`Downloaded: ${fileName}`);
  } catch (err) {
    console.error(`Error downloading ${item.src}:`, err.message);
  }
}

async function downloadAll() {
  for (const item of emojiArray) {
    await downloadImage(item);
  }
  console.log('All downloads completed!');
}

downloadAll();

表情下载完,后面就好办了——交给 AI 🤖。

3、组件实现

大概思路是有的,本质就是一个 contenteditable 的 div,组件实现完全让 AI 完成,但需要考虑一些特殊情况,要给出明确期望:

1️⃣ 光标位置管理
  • 长度达到限制时裁剪字符,统一将光标设置到末尾,防止位置异常(element-plus输入框效果如此)
  • 点击空白区域自动定位到末尾
2️⃣ 文本与图片双向转换

文本 → 图片

  • 使用防抖(200ms)避免频繁触发
  • 仅转换光标前的内容,光标后的内容保持不变
  • 通过正则匹配 [xxx] 格式进行转换
  • 关键:不在用户输入过程中转换,避免干扰输入体验

图片 → 文本

  • 文本节点直接提取 textContent
  • 图片节点提取 data-alt 属性转为文本
  • 过滤零宽字符 \u200B
3️⃣ 字符长度计算

精确计算混合内容长度:中文 1 个字符,英文/数字 0.5 个,表情 1 个。

4️⃣ 输入法兼容

处理中文输入法的组合事件:compositionstartcompositionupdatecompositionend,避免在拼音输入阶段触发转换。

5️⃣ 删除表情

确保删除时完整移除表情图片节点,不留残留。

最终效果:

动画.gif

💡总结

借助 AI 辅助开发,核心在于:告知 AI 需要处理的特殊情况,以及不断测试和调优。

只要明确需求规范和边界情况,就能高效实现功能。怎么有种从开发转测试的感觉。

❌
❌