☰
@emoji-mart/react 集成指南:在 React 应用中嵌入 Emoji Mart 表情选择器
2026/9/25 3:44:57 网站建设 项目流程
  • 前端
  • UI组件

【免费下载链接】emoji-mart

🏪 One component to pick them all

项目地址:https://gitcode.com/gh_mirrors/em/emoji-mart
点击查看免费下载

@emoji-mart/react是 Emoji Mart 官方为 React 生态提供的桥接包装层,它把基于 Preact 编写、可在任意前端框架下运行的 emoji-mart 核心 Picker 以纯 React 组件的形态暴露出来,让 React 开发者只需一行<Picker data={data} onEmojiSelect={...} />即可获得完整的表情选择能力。本指南将围绕该包装器的安装、基本用法、底层运行机制与全部可配置参数展开,读完你不仅能快速接入一个可用的表情选择器,还能理解包装器与核心库之间的数据同步方式,从而针对搜索、皮肤、主题、自定义表情等场景做出精准的定制。

一、包定位:React 生态中的 Emoji Mart 入口

Emoji Mart 采用 monorepo 结构(见根目录 package.json 的workspaces配置),核心代码分为若干相互独立的包。与 React 集成直接相关的是三个:

包名版本职责
emoji-mart5.6.0核心表情选择器,基于 Preact 实现,导出Picker、Emoji组件与初始化函数(见 packages/emoji-mart/package.json)
@emoji-mart/data1.2.1表情数据源,按 Emoji 版本(如 15)与图片风格(apple/google/twitter 等)组织 JSON,并附带 22 种语言的 i18n 文件(见 packages/emoji-mart-data/package.json)
@emoji-mart/react1.1.1React 包装器,对emoji-mart的Picker做薄封装(见 packages/emoji-mart-react/package.json)

@emoji-mart/react的定位可以从其 peerDependencies 看出端倪:它声明emoji-mart: ^5.2与react: ^16.8 || ^17 || ^18作为对等依赖,也就是说它自身不携带实现,而是依赖宿主项目中的核心包与 React 运行时。^16.8的下限意味着组件依赖 React Hooks(useRef、useEffect),这决定了其底层包装实现的基本形态。

二、安装

官方 README 给出的安装命令是一条命令同时安装三个包:

npm install --save emoji-mart @emoji-mart/data @emoji-mart/react

三个包缺一不可,职责划分明确:

  • emoji-mart:提供可运行的选择器实现;
  • @emoji-mart/data:提供被渲染的表情数据,是Picker的data参数的标准来源;
  • @emoji-mart/react:提供 React 组件形式的包装入口。

如果使用 Yarn 或 pnpm,等价命令为yarn add/pnpm add后跟同样的包名列表。注意emoji-mart是普通依赖而非可选依赖,因为@emoji-mart/react在运行时需要import { Picker } from 'emoji-mart'(见 packages/emoji-mart-react/react.tsx),缺少它会直接导致模块解析失败。

三、基本用法

官方文档给出的最小可用示例只有几行:

import data from '@emoji-mart/data' import Picker from '@emoji-mart/react' function App() { return ( <Picker data={data} onEmojiSelect={console.log} /> ) }

要点拆解:

  1. import data from '@emoji-mart/data':@emoji-mart/data的main字段指向sets/15/native.json(见 packages/emoji-mart-data/package.json),因此直接导入得到的是 Emoji 15 版本、native(系统原生)风格的表情数据集。
  2. <Picker data={data} />:data是必传的关键参数,它告诉 Picker 使用哪份数据渲染。
  3. onEmojiSelect={console.log}:用户点击任意表情时触发回调,回调签名是(emojiData, event)——第一个参数为解析后的表情数据对象(含id、name、skins、unified等字段),第二个参数为点击事件。这也是把表情写入输入框、聊天区或富文本编辑器的主要出口。

四、包装器内部机制:一次渲染、持续同步

@emoji-mart/react的整个实现只有 22 行(见 packages/emoji-mart-react/react.tsx),却完成了一个关键任务:把 Preact 组件的生命周期翻译成 React 组件的生命周期。

import React, { useEffect, useRef } from 'react' import { Picker } from 'emoji-mart' export default function EmojiPicker(props) { const ref = useRef(null) const instance = useRef(null) if (instance.current) { instance.current.update(props) } useEffect(() => { instance.current = new Picker({ ...props, ref }) return () => { instance.current = null } }, []) return React.createElement('div', { ref }) }

其运行逻辑可以拆解为三层:

  1. 挂载:useEffect以空依赖数组运行一次,创建一个真正的Picker实例(来自emoji-mart核心包),并把这个实例挂载到div元素上。核心Picker在componentDidMount阶段会执行注册事件监听、建立分类导航等初始化动作(见 packages/emoji-mart/src/components/Picker/Picker.tsx)。
  2. 更新:每次 React 渲染时,只要instance.current已存在,就调用instance.current.update(props)把最新的 props 同步给核心实例。核心Picker的componentWillReceiveProps会把这些 props 合并进内部状态,并在custom或categories变化时触发网格重置(见 packages/emoji-mart/src/components/Picker/Picker.tsx)。这一机制保证了 React 状态更新(如切换theme、set、skin)能实时反映到选择器 UI 上。
  3. 卸载:useEffect的清理函数将instance.current置空,核心实例随之销毁,事件监听与观察器被回收(对应componentWillUnmount中的unregister,见 packages/emoji-mart/src/components/Picker/Picker.tsx)。

从源码结构可以推断,这种"薄包装 + 实例托管"的设计有两个直接收益:React 侧几乎零开销(不需要维护重复的组件树),且能完整继承核心 Picker 的全部 props 与行为,做到功能零损失。

五、核心 Picker 的完整参数表

@emoji-mart/react直接透传所有 props 给核心Picker,因此核心库的完整配置项即是 React 组件的完整 API。这些参数、默认值与可选值集中定义在 packages/emoji-mart/src/components/Picker/PickerProps.ts 中:

5.1 外观与布局

参数默认值可选值 / 说明
themeautoauto/light/dark。auto会通过matchMedia('(prefers-color-scheme: dark)')跟随系统主题并监听变化(见 Picker.tsx)
setnativenative/apple/facebook/google/twitter,决定表情图片风格
skin11~6,默认肤色调
emojiSize24表情本体尺寸(px)
emojiButtonSize36单个表情按钮尺寸(px),同时参与网格行高与滚动边距计算
emojiButtonRadius100%表情按钮圆角
emojiButtonColorsnull按钮背景色数组,按位置循环取色,可做出多彩棋盘格效果
perLine9每行表情数量
dynamicWidthfalse开启后依据容器实际宽度动态计算每行数量(依赖ResizeObserver,见 Picker.tsx)
navPositiontop分类导航位置:top/bottom/none
previewPositionbottom预览区位置:top/bottom/none
searchPositionsticky搜索框位置:sticky/static/none
skinTonePositionpreview肤色调按钮位置:preview/search/none
iconsauto导航图标风格:auto/outline/solid
autoFocusfalse挂载后是否自动聚焦搜索框

5.2 数据与内容

参数默认值说明
datanull表情数据集,可以是对象或返回 Promise 的函数(延迟加载)。未传入时将从 jsDelivr CDN 按emojiVersion与set拉取(见 config.ts)
emojiVersion15数据版本,可选1/2/3/4/5/11/12/12.1/13/13.1/14/15,对应@emoji-mart/data的sets目录
localeen界面语言,支持ar/be/cs/de/es/fa/fi/fr/hi/it/ja/ko/nl/pl/pt/ru/sa/tr/uk/vi/zh共 22 种
i18nnull自定义文案覆盖,可为对象或函数
categoriesnull按分类 id 数组过滤并排序显示的分类
customnull自定义表情分类数组,每项含id、name、emojis等字段,会追加进Data.categories(见 config.ts)
categoryIconsnull按分类 id 提供自定义图标
exceptEmojis[]要排除的表情 id 数组
maxFrequentRows4“常用”分类最多显示的行数,同时控制本地存储记录的条数
noCountryFlagsfalsenative风格下隐藏国旗表情(依赖SafeFlags白名单过滤,见 config.ts)
noResultsEmojinull搜索无结果时预览区显示的占位表情
previewEmojinull自定义预览区默认表情

5.3 回调函数

参数说明
onEmojiSelect(emojiData, event)选择表情时的核心回调
onClickOutside(event)点击选择器外部时触发
onAddCustomEmoji()搜索无结果且配置了自定义表情时,显示"添加自定义表情"入口
getImageURL(set, unified)自定义图片加载 URL 生成器(非 native、非雪碧图模式时使用)
getSpritesheetURL(set)自定义雪碧图 URL 生成器

5.4 已废弃参数

stickySearch已被searchPosition取代。若同时传入stickySearch == false与searchPosition == 'sticky',控制台会输出弃用警告,并自动回退为static(见 Picker.tsx)。新代码请直接使用searchPosition。

六、数据加载与初始化原理

data参数看似简单,其背后是一整套初始化管线。核心Picker在渲染前会调用init(props)(见 config.ts),它做了以下几件事:

  1. 数据获取:data可以是对象、返回 Promise 的函数,或者省略。省略时按emojiVersion与set拼出 CDN 地址拉取 JSON,例如默认的sets/15/native.json。
  2. 结构补全:为数据补上emoticons(颜文字映射)与natives(原生字符映射)索引;将aliases(别名)回填到各表情的aliases数组;在分类列表头部插入frequent(常用)分类。
  3. i18n 加载:locale为en时直接使用内置英文文案,其他语言按需从 CDN 拉取对应 JSON。
  4. 过滤与整理:应用custom(追加自定义分类)、categories(筛选排序)、exceptEmojis(排除表情)、noCountryFlags(过滤国旗)等规则;为每个表情构建search索引字段(拼接 id、名称分词、关键词、颜文字、原生字符,见 config.ts)。
  5. 搜索索引重建:若上述步骤导致索引失效,会调用SearchIndex.reset()重建。

这也是为什么官方示例必须显式传入data——它让打包器把数据作为本地静态资源内联,避免运行时依赖 CDN 网络请求,对离线场景与构建产物可控性都更友好。

七、实战组合:一个定制化的 React 选择器

把上述参数组合起来,可以得到一个覆盖典型业务需求的完整示例:

import data from '@emoji-mart/data' import Picker from '@emoji-mart/react' import zh from '@emoji-mart/data/i18n/zh.json' function ChatEmojiPicker({ onPick, onClose }) { return ( <Picker data={data} // 本地内联数据,避免运行时拉 CDN locale="zh" // 中文界面 i18n={zh} // 显式传入中文文案,保证离线可用 theme="auto" // 跟随系统深浅色 set="apple" // 使用 Apple 风格表情图片 perLine={10} // 每行 10 个 emojiButtonSize={40} // 更大触控区域 previewPosition="top" // 预览区置顶 navPosition="bottom" // 分类导航置底 maxFrequentRows={2} // 常用分类只留两行 onEmojiSelect={onPick} // 表情选中回调 onClickOutside={onClose} // 点击外部关闭 /> ) }

使用时的注意事项:

  • set与data的匹配:set决定表情图片风格与数据包的sets子目录。若使用apple等非 native 风格,默认会从 emoji-datasource CDN 加载图片;如需完全离线,可通过getImageURL/getSpritesheetURL提供自托管资源地址(对应核心实现见 Emoji.tsx)。
  • 动态布局:在窄容器(如输入框弹层)中使用时建议开启dynamicWidth,Picker会借助ResizeObserver按容器实际宽度重算每行数量,避免表情按钮溢出。
  • 数据版本:默认数据为 Emoji 15 版本,可通过emojiVersion配合对应版本的@emoji-mart/data包灵活切换(数据包sets目录下提供 1~15 各版本,见 packages/emoji-mart-data/sets)。

八、性能设计:为什么千级表情也能流畅渲染

从核心源码可以观察到,Picker为渲染大量表情做了针对性优化,理解这些机制有助于在 React 项目中合理使用:

  • 按行懒渲染:Performance.rowsPerRender = 10,每 10 行为一组;只有进入视口的行才真正渲染(见 Picker.tsx 与renderCategories中的visibleRows判断)。
  • IntersectionObserver 双观察:一个观察分类区块以联动顶部导航高亮,另一个观察行可见性以驱动懒渲染(见 Picker.tsx)。
  • PureInlineComponent 隔离重绘:每个表情按钮被 HOC 包裹,只有selected、skin、size变化时才重渲染自身,避免整个网格随悬停状态抖动(见 packages/emoji-mart/src/components/HOCs/PureInlineComponent.ts)。
  • 键盘导航闭环:搜索框支持方向键移动高亮、Enter 选择、Escape 清空/失焦,并有mouseIsIgnored机制防止键盘操作后鼠标误触发(见 Picker.tsx)。

九、延伸阅读

  • 核心选择器实现:packages/emoji-mart/src/components/Picker/Picker.tsx
  • 全部 props 定义与默认值:packages/emoji-mart/src/components/Picker/PickerProps.ts
  • 数据初始化与 i18n 管线:packages/emoji-mart/src/config.ts
  • 表情渲染(图片/native/雪碧图三种模式):packages/emoji-mart/src/components/Emoji/Emoji.tsx
  • React 包装器实现:packages/emoji-mart-react/react.tsx
  • 数据包结构(sets 与 i18n):packages/emoji-mart-data
  • 主项目文档:README.md

综上,@emoji-mart/react是一个"薄到极致"的官方 React 适配层,真正的能力全部沉淀在emoji-mart核心库中。掌握安装命令、包装器的实例托管机制,以及透传 props 的完整参数表,即可在 React 16.8+ / 17 / 18 项目中快速落地一个支持搜索、分类导航、肤色调、深浅主题与自定义表情的完整表情选择器。

  • 前端
  • UI组件

【免费下载链接】emoji-mart

🏪 One component to pick them all

项目地址:https://gitcode.com/gh_mirrors/em/emoji-mart
点击查看免费下载
上一篇:Ladda:彻底改变按钮交互体验的加载指示器解决方案
下一篇:NodeMCU-Firmware终极指南:5个关键技巧避免ESP8266/ESP32中断配置系统崩溃

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询