不能直接用 document.execCommand 插入 emoji,因其在现代浏览器中已废弃,插入位置易错位且不支持肤色修饰符组合序列;应改用 Range + DocumentFragment 手动插入,并用 String.fromCodePoint 保证 UTF-16 安全性。

直接用 contenteditable + 原生 emoji 数据源做表情键盘,比引入整套 UI 库更轻、更可控——但必须自己处理光标位置、插入逻辑和皮肤变体兼容性。
为什么不能直接用 document.execCommand 插入 emoji
这个 API 在现代浏览器中已被废弃,Chrome 90+、Firefox 87+ 会静默失败;即使旧版能用,插入位置也常错位(尤其在 contenteditable 多行文本末尾或中间)。更关键的是它不支持「带肤色修饰符」的 emoji(如 ??、??),会把组合序列拆成乱码。
- 改用
Range+DocumentFragment手动插入,确保序列完整性 - 所有 emoji 必须以 UTF-16 安全字符串传入(推荐用
String.fromCodePoint()解析 Unicode 码点) - 插入前调用
getSelection().getRangeAt(0)获取当前光标位置,再用range.deleteContents()清除选区(避免覆盖文字)
如何让键盘面板真正“贴住”输入框底部(含滚动/缩放适配)
固定定位(position: fixed)在 iOS Safari 下极易失位:软键盘弹出时 viewport 高度突变,bottom: 0 会卡在屏幕底而非输入框下方;缩放后 getBoundingClientRect() 返回值也不准。
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
- 监听
focus事件,用inputElement.getBoundingClientRect()动态计算面板 top 值,而非依赖 CSS 固定定位 - 对 iOS 设备额外监听
resize和scroll,延迟 100ms 重算位置(防抖) - 面板容器加
transform: translateZ(0)强制硬件加速,避免 Safari 渲染撕裂
input 和 textarea 的 emoji 插入逻辑为什么必须分开写
input 是单行,插入后需手动触发 input 事件;textarea 是多行,插入时若光标在行中,要防止换行符被意外吞掉。二者底层 DOM 操作路径不同。
立即学习“前端免费学习笔记(深入)”;
- 对
input:取input.value,用字符串拼接插入,再赋值并 dispatchInputEvent - 对
textarea:必须用setSelectionRange控制光标,插入后手动调整新光标位置(否则光标会跳到开头) - 统一用
inputElement.addEventListener('input', handler)监听变化,不要混用change(它不响应实时输入)
最易被忽略的是 emoji 序列长度判断——JavaScript 的 .length 对组合 emoji 返回错误计数(如 ?? 实际是 5 个码点,.length === 7),导致光标偏移计算全错。必须用 Array.from(str).length 或 Intl.Segmenter(需检查兼容性)来真实统计字符数。


















