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

📋 背景

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

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

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

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

🚩 最终目标

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

🧩 实现步骤

1、获取表情包数据

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

javascript 复制代码
// 获取所有表情元素
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 用于拼接读取表情图片路径。

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

2、批量下载图片

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

javascript 复制代码
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️⃣ 输入法兼容

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

5️⃣ 删除表情

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

最终效果:

💡总结

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

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

相关推荐
java1234_小锋3 小时前
【技术专题】HTML5 网页技术 - HTML5 Canvas 基础以及动画入门
前端·html·html5
知了学历孙老师6 小时前
小自考的校考和统考,出题方和难度差在哪
java·大数据·前端
ShineWinsu8 小时前
对于JavaScript:操作元素的解析
开发语言·前端·javascript·面试·web·dom·元素
福兮说8 小时前
JSON 格式正确,数据就可靠吗?我用一份自编配置检查类型与空值
java·前端·json
程序员老赵10 小时前
Docker 部署青龙面板:轻松搭建定时任务管理平台
前端·docker·开源
Swot10 小时前
Asciidoctor 公式数字下标错位问题:原因分析与解决方案
前端
Swot10 小时前
leo-editor 中将 Markdown 内容转成 asciidoc 格式
前端
狒狒AI10 小时前
Remotion / GSAP+Three / HyperFrames / Skia 四栈实测:代码渲染知识视频的选栈方法(附开源技能)
前端·人工智能·aigc
修炼的dance10 小时前
浏览器里导出H.265,8.5秒和55.5秒差在硬件
前端
补码缩写10 小时前
WebCodecs选编码器,探测之后还要验解码和播放
前端