wechat-emojis 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/API.md +228 -0
- package/REACT_USAGE.md +456 -0
- package/README.md +251 -0
- package/assets/animal//345/217/221/346/212/226.png +0 -0
- package/assets/animal//347/214/252/345/244/264.png +0 -0
- package/assets/animal//350/267/263/350/267/263.png +0 -0
- package/assets/animal//350/275/254/345/234/210.png +0 -0
- package/assets/blessing//345/272/206/347/245/235.png +0 -0
- package/assets/blessing//347/203/237/350/212/261.png +0 -0
- package/assets/blessing//347/210/206/347/253/271.png +0 -0
- package/assets/blessing//347/231/274.png +0 -0
- package/assets/blessing//347/244/274/347/211/251.png +0 -0
- package/assets/blessing//347/246/217.png +0 -0
- package/assets/blessing//347/272/242/345/214/205.png +0 -0
- package/assets/face/666.png +0 -0
- package/assets/face/Emm.png +0 -0
- package/assets/face//344/272/262/344/272/262.png +0 -0
- package/assets/face//345/201/267/347/254/221.png +0 -0
- package/assets/face//345/202/262/346/205/242.png +0 -0
- package/assets/face//345/206/215/350/247/201.png +0 -0
- package/assets/face//345/212/240/346/262/271.png +0 -0
- package/assets/face//345/217/221/345/221/206.png +0 -0
- package/assets/face//345/217/221/346/200/222.png +0 -0
- package/assets/face//345/217/257/346/200/234.png +0 -0
- package/assets/face//345/217/263/345/223/274/345/223/274.png +0 -0
- package/assets/face//345/217/271/346/260/224.png +0 -0
- package/assets/face//345/220/203/347/223/234.png +0 -0
- package/assets/face//345/220/220.png +0 -0
- package/assets/face//345/221/262/347/211/231.png +0 -0
- package/assets/face//345/222/222/351/252/202.png +0 -0
- package/assets/face//345/223/207.png +0 -0
- package/assets/face//345/230/230.png +0 -0
- package/assets/face//345/230/277/345/223/210.png +0 -0
- package/assets/face//345/233/247.png +0 -0
- package/assets/face//345/233/260.png +0 -0
- package/assets/face//345/235/217/347/254/221.png +0 -0
- package/assets/face//345/244/247/345/223/255.png +0 -0
- package/assets/face//345/244/251/345/225/212.png +0 -0
- package/assets/face//345/244/261/346/234/233.png +0 -0
- package/assets/face//345/245/270/347/254/221.png +0 -0
- package/assets/face//345/245/275/347/232/204.png +0 -0
- package/assets/face//345/247/224/345/261/210.png +0 -0
- package/assets/face//345/256/263/347/276/236.png +0 -0
- package/assets/face//345/260/264/345/260/254.png +0 -0
- package/assets/face//345/276/227/346/204/217.png +0 -0
- package/assets/face//345/276/256/347/254/221.png +0 -0
- package/assets/face//345/277/253/345/223/255/344/272/206.png +0 -0
- package/assets/face//346/201/220/346/203/247.png +0 -0
- package/assets/face//346/202/240/351/227/262.png +0 -0
- package/assets/face//346/203/212/346/201/220.png +0 -0
- package/assets/face//346/203/212/350/256/266.png +0 -0
- package/assets/face//346/204/211/345/277/253.png +0 -0
- package/assets/face//346/206/250/347/254/221.png +0 -0
- package/assets/face//346/211/223/350/204/270.png +0 -0
- package/assets/face//346/212/223/347/213/202.png +0 -0
- package/assets/face//346/212/240/351/274/273.png +0 -0
- package/assets/face//346/215/202/350/204/270.png +0 -0
- package/assets/face//346/222/207/345/230/264.png +0 -0
- package/assets/face//346/223/246/346/261/227.png +0 -0
- package/assets/face//346/225/262/346/211/223.png +0 -0
- package/assets/face//346/227/240/350/257/255.png +0 -0
- package/assets/face//346/227/272/346/237/264.png +0 -0
- package/assets/face//346/231/225.png +0 -0
- package/assets/face//346/234/272/346/231/272.png +0 -0
- package/assets/face//346/261/227.png +0 -0
- package/assets/face//346/265/201/346/263/252.png +0 -0
- package/assets/face//347/224/237/347/227/205.png +0 -0
- package/assets/face//347/226/221/351/227/256.png +0 -0
- package/assets/face//347/231/275/347/234/274.png +0 -0
- package/assets/face//347/232/261/347/234/211.png +0 -0
- package/assets/face//347/235/241.png +0 -0
- package/assets/face//347/240/264/346/266/225/344/270/272/347/254/221.png +0 -0
- package/assets/face//347/244/276/344/274/232.png +0 -0
- package/assets/face//347/254/221/350/204/270.png +0 -0
- package/assets/face//347/277/273/347/231/275/347/234/274.png +0 -0
- package/assets/face//350/200/266.png +0 -0
- package/assets/face//350/204/270/347/272/242.png +0 -0
- package/assets/face//350/211/262.png +0 -0
- package/assets/face//350/213/246/346/266/251.png +0 -0
- package/assets/face//350/241/260.png +0 -0
- package/assets/face//350/243/202/345/274/200.png +0 -0
- package/assets/face//350/256/251/346/210/221/347/234/213/347/234/213.png +0 -0
- package/assets/face//350/260/203/347/232/256.png +0 -0
- package/assets/face//351/204/231/350/247/206.png +0 -0
- package/assets/face//351/227/255/345/230/264.png +0 -0
- package/assets/face//351/230/264/351/231/251.png +0 -0
- package/assets/face//351/232/276/350/277/207.png +0 -0
- package/assets/face//351/252/267/351/253/205.png +0 -0
- package/assets/face//351/274/223/346/216/214.png +0 -0
- package/assets/gesture/OK.png +0 -0
- package/assets/gesture//345/213/276/345/274/225.png +0 -0
- package/assets/gesture//345/220/210/345/215/201.png +0 -0
- package/assets/gesture//345/274/261.png +0 -0
- package/assets/gesture//345/274/272.png +0 -0
- package/assets/gesture//345/276/227/346/204/217.png +0 -0
- package/assets/gesture//346/212/261/346/213/263.png +0 -0
- package/assets/gesture//346/213/245/346/212/261.png +0 -0
- package/assets/gesture//346/213/263/345/244/264.png +0 -0
- package/assets/gesture//346/217/241/346/211/213.png +0 -0
- package/assets/gesture//350/200/266.png +0 -0
- package/assets/gesture//350/203/234/345/210/251.png +0 -0
- package/assets/other//344/276/277/344/276/277.png +0 -0
- package/assets/other//345/207/213/350/260/242.png +0 -0
- package/assets/other//345/222/226/345/225/241.png +0 -0
- package/assets/other//345/225/244/351/205/222.png +0 -0
- package/assets/other//345/230/264/345/224/207.png +0 -0
- package/assets/other//345/244/252/351/230/263.png +0 -0
- package/assets/other//345/245/213/346/226/227.png +0 -0
- package/assets/other//345/277/203/347/242/216.png +0 -0
- package/assets/other//346/231/232/345/256/211.png +0 -0
- package/assets/other//347/202/270/345/274/271.png +0 -0
- package/assets/other//347/210/206/347/217/240.png +0 -0
- package/assets/other//347/210/206/347/253/271.png +0 -0
- package/assets/other//347/210/261/345/277/203.png +0 -0
- package/assets/other//350/217/234/345/210/200.png +0 -0
- package/assets/other//350/233/213/347/263/225.png +0 -0
- package/assets/other//351/262/234/350/212/261.png +0 -0
- package/package.json +49 -0
- package/wechatEmoji.js +314 -0
- package/wechatEmoji.ts +364 -0
package/API.md
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# 微信表情包 TypeScript API 文档
|
|
2
|
+
|
|
3
|
+
## 概述
|
|
4
|
+
|
|
5
|
+
`wechatEmoji.ts` 提供了完整的 TypeScript 支持,让你可以类型安全地访问微信表情包资源。
|
|
6
|
+
|
|
7
|
+
## 安装和使用
|
|
8
|
+
|
|
9
|
+
### 1. 通过 NPM 安装(推荐)
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# 安装包
|
|
13
|
+
npm install wechat-emojis
|
|
14
|
+
|
|
15
|
+
# 复制表情资源到项目的 public 目录(重要)
|
|
16
|
+
mkdir -p public/assets
|
|
17
|
+
cp -r node_modules/wechat-emojis/assets/* public/assets/
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
使用 NPM 包:
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
import WeChatEmojis, {
|
|
24
|
+
EmojiCategory,
|
|
25
|
+
getEmojiPath,
|
|
26
|
+
getEmojisByCategory,
|
|
27
|
+
searchEmojis
|
|
28
|
+
} from 'wechat-emojis';
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### 2. 直接使用 TypeScript 源文件
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import WeChatEmojis, {
|
|
35
|
+
EmojiCategory,
|
|
36
|
+
getEmojiPath,
|
|
37
|
+
getEmojisByCategory,
|
|
38
|
+
searchEmojis
|
|
39
|
+
} from './wechatEmoji';
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### 3. 编译后使用 JavaScript
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# 编译 TypeScript
|
|
46
|
+
npx tsc wechatEmoji.ts --target es2017 --module commonjs
|
|
47
|
+
|
|
48
|
+
# 在 Node.js 中使用
|
|
49
|
+
const { getEmojiPath, EmojiCategory } = require('./wechatEmoji.js');
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## API 参考
|
|
53
|
+
|
|
54
|
+
### 类型定义
|
|
55
|
+
|
|
56
|
+
#### `EmojiCategory` 枚举
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
enum EmojiCategory {
|
|
60
|
+
FACE = 'face', // 人脸表情
|
|
61
|
+
GESTURE = 'gesture', // 手势表情
|
|
62
|
+
ANIMAL = 'animal', // 动物表情
|
|
63
|
+
BLESSING = 'blessing', // 祝福表情
|
|
64
|
+
OTHER = 'other' // 其他表情
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
#### `EmojiInfo` 接口
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
interface EmojiInfo {
|
|
72
|
+
name: string; // 表情名称
|
|
73
|
+
category: EmojiCategory; // 表情类别
|
|
74
|
+
path: string; // 图片文件路径
|
|
75
|
+
englishName?: string; // 英文名称(可选)
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
#### `EmojiName` 类型
|
|
80
|
+
|
|
81
|
+
包含所有有效表情名称的联合类型,提供编译时类型检查。
|
|
82
|
+
|
|
83
|
+
### 核心函数
|
|
84
|
+
|
|
85
|
+
#### `getEmojiPath(name: EmojiName): string | null`
|
|
86
|
+
|
|
87
|
+
获取表情图片路径。
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
const path = getEmojiPath('微笑'); // 'assets/face/微笑.png'
|
|
91
|
+
const invalid = getEmojiPath('不存在'); // null
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
#### `getEmojiInfo(name: EmojiName): EmojiInfo | null`
|
|
95
|
+
|
|
96
|
+
获取表情详细信息。
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
const emoji = getEmojiInfo('微笑');
|
|
100
|
+
// { name: '微笑', category: EmojiCategory.FACE, path: 'assets/face/微笑.png' }
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
#### `getEmojisByCategory(category: EmojiCategory): EmojiInfo[]`
|
|
104
|
+
|
|
105
|
+
按类别获取表情列表。
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
const faceEmojis = getEmojisByCategory(EmojiCategory.FACE);
|
|
109
|
+
console.log(`人脸表情数量: ${faceEmojis.length}`); // 75
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
#### `getAllEmojis(): EmojiInfo[]`
|
|
113
|
+
|
|
114
|
+
获取所有表情信息。
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
const allEmojis = getAllEmojis();
|
|
118
|
+
console.log(`总表情数量: ${allEmojis.length}`); // 108
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
#### `searchEmojis(keyword: string): EmojiInfo[]`
|
|
122
|
+
|
|
123
|
+
搜索包含关键词的表情。
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
const laughEmojis = searchEmojis('笑');
|
|
127
|
+
// 返回包含 '微笑', '偷笑', '坏笑' 等的表情
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
#### `hasEmoji(name: string): name is EmojiName`
|
|
131
|
+
|
|
132
|
+
检查表情是否存在(类型守卫)。
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
if (hasEmoji('微笑')) {
|
|
136
|
+
// TypeScript 知道这里 '微笑' 是有效的 EmojiName
|
|
137
|
+
const path = getEmojiPath('微笑');
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
#### `getEmojiNames(category?: EmojiCategory): string[]`
|
|
142
|
+
|
|
143
|
+
获取表情名称列表。
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
const allNames = getEmojiNames();
|
|
147
|
+
const faceNames = getEmojiNames(EmojiCategory.FACE);
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
#### `getRandomEmoji(category?: EmojiCategory): EmojiInfo`
|
|
151
|
+
|
|
152
|
+
随机获取表情。
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
const randomEmoji = getRandomEmoji();
|
|
156
|
+
const randomFaceEmoji = getRandomEmoji(EmojiCategory.FACE);
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## 使用示例
|
|
160
|
+
|
|
161
|
+
### React 组件示例
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
import React from 'react';
|
|
165
|
+
import { getEmojiPath, getEmojisByCategory, EmojiCategory } from 'wechat-emojis';
|
|
166
|
+
|
|
167
|
+
const EmojiPicker: React.FC = () => {
|
|
168
|
+
const faceEmojis = getEmojisByCategory(EmojiCategory.FACE);
|
|
169
|
+
|
|
170
|
+
return (
|
|
171
|
+
<div className="emoji-picker">
|
|
172
|
+
{faceEmojis.map(emoji => (
|
|
173
|
+
<img
|
|
174
|
+
key={emoji.name}
|
|
175
|
+
src={getEmojiPath(emoji.name)}
|
|
176
|
+
alt={emoji.name}
|
|
177
|
+
title={emoji.name}
|
|
178
|
+
className="emoji-item"
|
|
179
|
+
onClick={() => console.log(`选择了: ${emoji.name}`)}
|
|
180
|
+
/>
|
|
181
|
+
))}
|
|
182
|
+
</div>
|
|
183
|
+
);
|
|
184
|
+
};
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Vue 组件示例
|
|
188
|
+
|
|
189
|
+
```vue
|
|
190
|
+
<template>
|
|
191
|
+
<div class="emoji-grid">
|
|
192
|
+
<img
|
|
193
|
+
v-for="emoji in emojis"
|
|
194
|
+
:key="emoji.name"
|
|
195
|
+
:src="getEmojiPath(emoji.name)"
|
|
196
|
+
:alt="emoji.name"
|
|
197
|
+
:title="emoji.name"
|
|
198
|
+
@click="selectEmoji(emoji)"
|
|
199
|
+
/>
|
|
200
|
+
</div>
|
|
201
|
+
</template>
|
|
202
|
+
|
|
203
|
+
<script setup lang="ts">
|
|
204
|
+
import { getEmojisByCategory, getEmojiPath, EmojiCategory } from 'wechat-emojis';
|
|
205
|
+
|
|
206
|
+
const emojis = getEmojisByCategory(EmojiCategory.FACE);
|
|
207
|
+
|
|
208
|
+
const selectEmoji = (emoji: EmojiInfo) => {
|
|
209
|
+
console.log(`选择了表情: ${emoji.name}`);
|
|
210
|
+
};
|
|
211
|
+
</script>
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## 数据统计
|
|
215
|
+
|
|
216
|
+
- **总表情数量**: 108 个
|
|
217
|
+
- **人脸表情**: 75 个
|
|
218
|
+
- **手势表情**: 7 个
|
|
219
|
+
- **动物表情**: 4 个
|
|
220
|
+
- **祝福表情**: 7 个
|
|
221
|
+
- **其他表情**: 15 个
|
|
222
|
+
|
|
223
|
+
## 注意事项
|
|
224
|
+
|
|
225
|
+
1. **类型安全**: 使用 `EmojiName` 类型可以在编译时检查表情名称的有效性
|
|
226
|
+
2. **路径相对性**: 返回的路径是相对于项目根目录的
|
|
227
|
+
3. **兼容性**: 编译目标为 ES2017,兼容现代浏览器和 Node.js
|
|
228
|
+
4. **性能**: 所有数据在模块加载时预计算,查询性能优秀
|
package/REACT_USAGE.md
ADDED
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
# React 项目中使用微信表情包
|
|
2
|
+
|
|
3
|
+
本指南详细介绍如何在React项目中集成和使用微信表情包模块。
|
|
4
|
+
|
|
5
|
+
## 📦 安装和配置
|
|
6
|
+
|
|
7
|
+
### 方式一:使用npm包(推荐)
|
|
8
|
+
|
|
9
|
+
1. **安装包**:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install wechat-emojis
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
2. **复制资源文件**:
|
|
16
|
+
由于npm包中的图片资源需要被复制到你的项目public目录,请执行以下命令:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# 复制表情资源到你的项目
|
|
20
|
+
cp -r node_modules/wechat-emojis/assets/* public/assets/
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
你也可以在 `package.json` 中配置一个脚本,在安装后自动完成复制:
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
// package.json
|
|
27
|
+
{
|
|
28
|
+
"scripts": {
|
|
29
|
+
"postinstall": "cp -r node_modules/wechat-emojis/assets/* public/assets/"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
3. **在React项目中使用**:
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
// 直接从npm包导入
|
|
38
|
+
import {
|
|
39
|
+
getEmojiPath,
|
|
40
|
+
getEmojisByCategory,
|
|
41
|
+
EmojiCategory,
|
|
42
|
+
type EmojiName
|
|
43
|
+
} from 'wechat-emojis';
|
|
44
|
+
|
|
45
|
+
// 使用示例
|
|
46
|
+
const WeChatEmoji: React.FC<{name: EmojiName}> = ({ name }) => {
|
|
47
|
+
const emojiPath = getEmojiPath(name);
|
|
48
|
+
// 确保你的 public 目录配置正确,可以直接访问 /assets/
|
|
49
|
+
return <img src={`/${emojiPath}`} alt={name} width={24} height={24} />;
|
|
50
|
+
};
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 方式二:直接复制文件
|
|
54
|
+
|
|
55
|
+
1. **复制必要文件到React项目**:
|
|
56
|
+
```bash
|
|
57
|
+
# 在你的React项目根目录下
|
|
58
|
+
mkdir -p src/utils/wechat-emojis
|
|
59
|
+
mkdir -p public/assets
|
|
60
|
+
|
|
61
|
+
# 复制TypeScript模块
|
|
62
|
+
cp path/to/wechatEmoji.ts src/utils/wechat-emojis/
|
|
63
|
+
cp path/to/wechatEmoji.js src/utils/wechat-emojis/
|
|
64
|
+
|
|
65
|
+
# 复制表情资源到public目录
|
|
66
|
+
cp -r path/to/assets/* public/assets/
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
2. **调整图片路径**(重要):
|
|
70
|
+
由于React项目中public目录的资源访问方式,需要修改 `wechatEmoji.ts` 中的图片路径,将所有 `'assets/'` 替换为 `'/assets/'`。
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
## 🚀 基础使用
|
|
74
|
+
|
|
75
|
+
### 1. 导入模块
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
// 从 npm 包导入 (推荐)
|
|
79
|
+
import {
|
|
80
|
+
getEmojiPath,
|
|
81
|
+
getEmojisByCategory,
|
|
82
|
+
EmojiCategory,
|
|
83
|
+
type EmojiName
|
|
84
|
+
} from 'wechat-emojis';
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### 2. 创建表情组件
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
// src/components/WeChatEmoji.tsx
|
|
91
|
+
import React from 'react';
|
|
92
|
+
import { getEmojiPath, type EmojiName } from 'wechat-emojis';
|
|
93
|
+
|
|
94
|
+
interface WeChatEmojiProps {
|
|
95
|
+
name: EmojiName;
|
|
96
|
+
size?: number;
|
|
97
|
+
className?: string;
|
|
98
|
+
alt?: string;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const WeChatEmoji: React.FC<WeChatEmojiProps> = ({
|
|
102
|
+
name,
|
|
103
|
+
size = 24,
|
|
104
|
+
className = '',
|
|
105
|
+
alt
|
|
106
|
+
}) => {
|
|
107
|
+
const emojiPath = getEmojiPath(name);
|
|
108
|
+
|
|
109
|
+
if (!emojiPath) {
|
|
110
|
+
console.warn(`表情 "${name}" 不存在`);
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return (
|
|
115
|
+
<img
|
|
116
|
+
src={emojiPath}
|
|
117
|
+
alt={alt || name}
|
|
118
|
+
width={size}
|
|
119
|
+
height={size}
|
|
120
|
+
className={`wechat-emoji ${className}`}
|
|
121
|
+
style={{
|
|
122
|
+
display: 'inline-block',
|
|
123
|
+
verticalAlign: 'middle'
|
|
124
|
+
}}
|
|
125
|
+
/>
|
|
126
|
+
);
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
export default WeChatEmoji;
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### 3. 使用表情组件
|
|
133
|
+
|
|
134
|
+
```tsx
|
|
135
|
+
// src/App.tsx
|
|
136
|
+
import React from 'react';
|
|
137
|
+
import WeChatEmoji from './components/WeChatEmoji';
|
|
138
|
+
|
|
139
|
+
function App() {
|
|
140
|
+
return (
|
|
141
|
+
<div className="App">
|
|
142
|
+
<h1>微信表情示例</h1>
|
|
143
|
+
|
|
144
|
+
{/* 基础使用 */}
|
|
145
|
+
<p>
|
|
146
|
+
你好 <WeChatEmoji name="微笑" size={20} />
|
|
147
|
+
今天天气真好 <WeChatEmoji name="太阳" size={20} />
|
|
148
|
+
</p>
|
|
149
|
+
|
|
150
|
+
{/* 不同尺寸 */}
|
|
151
|
+
<div>
|
|
152
|
+
<WeChatEmoji name="大哭" size={16} />
|
|
153
|
+
<WeChatEmoji name="大哭" size={24} />
|
|
154
|
+
<WeChatEmoji name="大哭" size={32} />
|
|
155
|
+
</div>
|
|
156
|
+
</div>
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export default App;
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## 🎨 高级使用示例
|
|
164
|
+
|
|
165
|
+
### 1. 表情选择器组件
|
|
166
|
+
|
|
167
|
+
```tsx
|
|
168
|
+
// src/components/EmojiPicker.tsx
|
|
169
|
+
import React, { useState } from 'react';
|
|
170
|
+
import {
|
|
171
|
+
getEmojisByCategory,
|
|
172
|
+
EmojiCategory,
|
|
173
|
+
type EmojiInfo
|
|
174
|
+
} from 'wechat-emojis';
|
|
175
|
+
import WeChatEmoji from './WeChatEmoji';
|
|
176
|
+
|
|
177
|
+
interface EmojiPickerProps {
|
|
178
|
+
onEmojiSelect: (emoji: EmojiInfo) => void;
|
|
179
|
+
categories?: EmojiCategory[];
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const EmojiPicker: React.FC<EmojiPickerProps> = ({
|
|
183
|
+
onEmojiSelect,
|
|
184
|
+
categories = [
|
|
185
|
+
EmojiCategory.FACE,
|
|
186
|
+
EmojiCategory.GESTURE,
|
|
187
|
+
EmojiCategory.ANIMAL,
|
|
188
|
+
EmojiCategory.BLESSING,
|
|
189
|
+
EmojiCategory.OTHER
|
|
190
|
+
]
|
|
191
|
+
}) => {
|
|
192
|
+
const [activeCategory, setActiveCategory] = useState<EmojiCategory>(EmojiCategory.FACE);
|
|
193
|
+
|
|
194
|
+
const categoryNames = {
|
|
195
|
+
[EmojiCategory.FACE]: '人脸',
|
|
196
|
+
[EmojiCategory.GESTURE]: '手势',
|
|
197
|
+
[EmojiCategory.ANIMAL]: '动物',
|
|
198
|
+
[EmojiCategory.BLESSING]: '祝福',
|
|
199
|
+
[EmojiCategory.OTHER]: '其他'
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
return (
|
|
203
|
+
<div className="emoji-picker">
|
|
204
|
+
{/* 分类标签 */}
|
|
205
|
+
<div className="emoji-categories">
|
|
206
|
+
{categories.map(category => (
|
|
207
|
+
<button
|
|
208
|
+
key={category}
|
|
209
|
+
className={`category-btn ${activeCategory === category ? 'active' : ''}`}
|
|
210
|
+
onClick={() => setActiveCategory(category)}
|
|
211
|
+
>
|
|
212
|
+
{categoryNames[category]}
|
|
213
|
+
</button>
|
|
214
|
+
))}
|
|
215
|
+
</div>
|
|
216
|
+
|
|
217
|
+
{/* 表情网格 */}
|
|
218
|
+
<div className="emoji-grid">
|
|
219
|
+
{getEmojisByCategory(activeCategory).map(emoji => (
|
|
220
|
+
<button
|
|
221
|
+
key={emoji.name}
|
|
222
|
+
className="emoji-item"
|
|
223
|
+
onClick={() => onEmojiSelect(emoji)}
|
|
224
|
+
title={emoji.name}
|
|
225
|
+
>
|
|
226
|
+
<WeChatEmoji name={emoji.name} size={24} />
|
|
227
|
+
</button>
|
|
228
|
+
))}
|
|
229
|
+
</div>
|
|
230
|
+
</div>
|
|
231
|
+
);
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
export default EmojiPicker;
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### 2. 聊天消息组件
|
|
238
|
+
|
|
239
|
+
```tsx
|
|
240
|
+
// src/components/ChatMessage.tsx
|
|
241
|
+
import React from 'react';
|
|
242
|
+
import { getEmojiPath, type EmojiName } from 'wechat-emojis';
|
|
243
|
+
|
|
244
|
+
interface ChatMessageProps {
|
|
245
|
+
content: string;
|
|
246
|
+
emojiSize?: number;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const ChatMessage: React.FC<ChatMessageProps> = ({ content, emojiSize = 20 }) => {
|
|
250
|
+
// 解析消息中的表情标记,例如 [微笑] → 表情图片
|
|
251
|
+
const parseEmojis = (text: string) => {
|
|
252
|
+
const emojiRegex = /\[([^\]]+)\]/g;
|
|
253
|
+
const parts = [];
|
|
254
|
+
let lastIndex = 0;
|
|
255
|
+
let match;
|
|
256
|
+
|
|
257
|
+
while ((match = emojiRegex.exec(text)) !== null) {
|
|
258
|
+
// 添加表情前的文本
|
|
259
|
+
if (match.index > lastIndex) {
|
|
260
|
+
parts.push(text.slice(lastIndex, match.index));
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// 添加表情
|
|
264
|
+
const emojiName = match[1] as EmojiName;
|
|
265
|
+
const emojiPath = getEmojiPath(emojiName);
|
|
266
|
+
|
|
267
|
+
if (emojiPath) {
|
|
268
|
+
parts.push(
|
|
269
|
+
<img
|
|
270
|
+
key={`emoji-${match.index}`}
|
|
271
|
+
src={emojiPath}
|
|
272
|
+
alt={emojiName}
|
|
273
|
+
width={emojiSize}
|
|
274
|
+
height={emojiSize}
|
|
275
|
+
style={{
|
|
276
|
+
display: 'inline-block',
|
|
277
|
+
verticalAlign: 'middle',
|
|
278
|
+
margin: '0 2px'
|
|
279
|
+
}}
|
|
280
|
+
/>
|
|
281
|
+
);
|
|
282
|
+
} else {
|
|
283
|
+
// 如果表情不存在,保留原文本
|
|
284
|
+
parts.push(match[0]);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
lastIndex = match.index + match[0].length;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// 添加剩余文本
|
|
291
|
+
if (lastIndex < text.length) {
|
|
292
|
+
parts.push(text.slice(lastIndex));
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
return parts;
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
return (
|
|
299
|
+
<div className="chat-message">
|
|
300
|
+
{parseEmojis(content)}
|
|
301
|
+
</div>
|
|
302
|
+
);
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
export default ChatMessage;
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
## 💡 使用技巧和最佳实践
|
|
309
|
+
|
|
310
|
+
### 1. 性能优化
|
|
311
|
+
|
|
312
|
+
```tsx
|
|
313
|
+
// 使用 React.memo 优化表情组件
|
|
314
|
+
const WeChatEmoji = React.memo<WeChatEmojiProps>(({ name, size, className, alt }) => {
|
|
315
|
+
// ... 组件实现
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
// 预加载常用表情
|
|
319
|
+
const preloadEmojis = (emojiNames: EmojiName[]) => {
|
|
320
|
+
emojiNames.forEach(name => {
|
|
321
|
+
const path = getEmojiPath(name);
|
|
322
|
+
if (path) {
|
|
323
|
+
const img = new Image();
|
|
324
|
+
img.src = path;
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
};
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### 2. 错误处理
|
|
331
|
+
|
|
332
|
+
```tsx
|
|
333
|
+
const WeChatEmoji: React.FC<WeChatEmojiProps> = ({ name, size = 24, fallback }) => {
|
|
334
|
+
const [hasError, setHasError] = useState(false);
|
|
335
|
+
const emojiPath = getEmojiPath(name);
|
|
336
|
+
|
|
337
|
+
if (!emojiPath || hasError) {
|
|
338
|
+
return fallback || <span>[{name}]</span>;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
return (
|
|
342
|
+
<img
|
|
343
|
+
src={emojiPath}
|
|
344
|
+
alt={name}
|
|
345
|
+
width={size}
|
|
346
|
+
height={size}
|
|
347
|
+
onError={() => setHasError(true)}
|
|
348
|
+
/>
|
|
349
|
+
);
|
|
350
|
+
};
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### 3. 样式定制
|
|
354
|
+
|
|
355
|
+
```css
|
|
356
|
+
/* src/styles/emoji.css */
|
|
357
|
+
.wechat-emoji {
|
|
358
|
+
display: inline-block;
|
|
359
|
+
vertical-align: middle;
|
|
360
|
+
user-select: none;
|
|
361
|
+
pointer-events: none;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
.emoji-picker {
|
|
365
|
+
border: 1px solid #e0e0e0;
|
|
366
|
+
border-radius: 8px;
|
|
367
|
+
padding: 12px;
|
|
368
|
+
background: white;
|
|
369
|
+
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
.emoji-categories {
|
|
373
|
+
display: flex;
|
|
374
|
+
gap: 8px;
|
|
375
|
+
margin-bottom: 12px;
|
|
376
|
+
border-bottom: 1px solid #f0f0f0;
|
|
377
|
+
padding-bottom: 8px;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
.category-btn {
|
|
381
|
+
padding: 6px 12px;
|
|
382
|
+
border: none;
|
|
383
|
+
background: #f5f5f5;
|
|
384
|
+
border-radius: 4px;
|
|
385
|
+
cursor: pointer;
|
|
386
|
+
font-size: 12px;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
.category-btn.active {
|
|
390
|
+
background: #1890ff;
|
|
391
|
+
color: white;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
.emoji-grid {
|
|
395
|
+
display: grid;
|
|
396
|
+
grid-template-columns: repeat(8, 1fr);
|
|
397
|
+
gap: 4px;
|
|
398
|
+
max-height: 200px;
|
|
399
|
+
overflow-y: auto;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
.emoji-item {
|
|
403
|
+
padding: 6px;
|
|
404
|
+
border: none;
|
|
405
|
+
background: transparent;
|
|
406
|
+
border-radius: 4px;
|
|
407
|
+
cursor: pointer;
|
|
408
|
+
display: flex;
|
|
409
|
+
align-items: center;
|
|
410
|
+
justify-content: center;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
.emoji-item:hover {
|
|
414
|
+
background: #f0f0f0;
|
|
415
|
+
}
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
## 🔧 TypeScript 支持
|
|
419
|
+
|
|
420
|
+
项目完全支持TypeScript,提供完整的类型定义:
|
|
421
|
+
|
|
422
|
+
```typescript
|
|
423
|
+
import type {
|
|
424
|
+
EmojiName, // 所有表情名称的联合类型
|
|
425
|
+
EmojiInfo, // 表情信息接口
|
|
426
|
+
EmojiCategory // 表情分类枚举
|
|
427
|
+
} from 'wechat-emojis';
|
|
428
|
+
|
|
429
|
+
// 类型安全的表情使用
|
|
430
|
+
const validEmoji: EmojiName = '微笑'; // ✅ 正确
|
|
431
|
+
const invalidEmoji: EmojiName = '不存在'; // ❌ TypeScript 错误
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
## 🚨 注意事项
|
|
435
|
+
|
|
436
|
+
1. **图片路径**:确保assets目录位于public文件夹根目录,并且代码中引用的路径是正确的(例如,以 `/assets/` 开头)。
|
|
437
|
+
2. **性能**:大量表情时考虑懒加载和虚拟滚动
|
|
438
|
+
3. **兼容性**:确保目标浏览器支持所需的图片格式
|
|
439
|
+
4. **版权**:注意表情包的使用权限和版权问题
|
|
440
|
+
|
|
441
|
+
## 📱 移动端适配
|
|
442
|
+
|
|
443
|
+
```css
|
|
444
|
+
/* 移动端优化 */
|
|
445
|
+
@media (max-width: 768px) {
|
|
446
|
+
.emoji-grid {
|
|
447
|
+
grid-template-columns: repeat(6, 1fr);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
.emoji-item {
|
|
451
|
+
padding: 8px;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
这样你就可以在React项目中完美使用微信表情包了!
|