在 Web 中实现表情符号的输入
SegmentFault
共 11163字,需浏览 23分钟
·
2021-03-14 13:32
来自微博和微信的两种风格
一种是像微信这样,只用纯文本,通过类似[旺柴]这样的符号标识来替代表情,最后输出时再显示成真正的表情。 另一种是像微博这样,所见即所得,输入框本身就是表情和文字混合在一起。
表情图和文字在一起的场景
<div contenteditable="true"></div>
表情的显示
<div contenteditable="true">
一条带表情<img src="/path/to/emoji/3.gif"><img src="/path/to/emoji/3.gif">的微博<img src="/path/to/emoji/9.gif">
</div>
表情输入功能的要点
点击下方的表情,就将该表情对应的HTML代码插入到输入框<div>。 表情HTML代码插入的位置要符合输入框<div>的当前光标位置。
Selection 和 Range
一种是有一个不断闪烁的光标,表示着当前正在输入或准备输入的位置。它一般只出现在网页的可以输入的元素内,比如文本输入框。 另一种是一部分内容呈现蓝底白字(这个颜色可以修改,但默认是这个颜色)的状态,表示当前被选中。它可以出现在任意的网页元素内,我们也常用来部分复制网页内容。
Range的设计意义
getRangeAt(i) - 按索引获取Selection的当前Range。除Firefox外,其他浏览器只固定使用索引0。 addRange(range) - 将range应用到Selection。除Firefox外,如果Selection当前已经有其他Range,将忽略此方法调用。 removeRange(range) - 从Selection中取消应用range。 removeAllRanges() - 取消应用所有Range。 empty() - 等同于removeAllRanges()。
符合光标位置的表情插入
<div
ref="inputBox"
class="input-box"
contenteditable="true"></div>
document.onselectionchange = () => {
let selection = document.getSelection();
if (selection.rangeCount > 0) {
const range = selection.getRangeAt(0);
if (vmEmoji.$refs.inputBox.contains(range.commonAncestorContainer)) {
rangeOfInputBox = range;
}
}
};
insertEmoji (name) {
let emojiEl = document.createElement("img");
emojiEl.src = `${this.emoji.path}${name}${this.emoji.suffix}`;
if (!rangeOfInputBox) {
rangeOfInputBox = new Range();
rangeOfInputBox.selectNodeContents(this.$refs.inputBox);
}
if (rangeOfInputBox.collapsed) {
rangeOfInputBox.insertNode(emojiEl);
} else {
rangeOfInputBox.deleteContents();
rangeOfInputBox.insertNode(emojiEl);
}
rangeOfInputBox.collapse(false);
}
完善点击表情时的光标置位
<div
ref="inputBox"
@click="handleBoxClick"
class="input-box"
contenteditable="true"></div>
handleBoxClick (event) {
let target = event.target;
this.setCaretForEmoji(target);
},
setCaretForEmoji (target) {
if (target.tagName.toLowerCase() === "img") {
let range = new Range();
range.setStartBefore(target);
range.collapse(true);
document.getSelection().removeAllRanges();
document.getSelection().addRange(range);
}
},
用纯文本符号来替代表情的场景
<input
ref="formInput"
@keydown="handleFormInputKeydown"
class="form-input"
type="text">
点击下方的表情,就将该表情对应的纯文本符号插入到输入框<input>。 纯文本符号的插入位置要符合输入框<input>的当前光标位置。
按光标位置来插入纯文本
input.selectionStart - 选择的起始位置。它的值是一个索引数字,比如6。 input.selectionEnd - 选择的结尾位置。值的格式同上。 input.selectionDirection - 选择的方向。可选值"forward","backward"和"none"。一般对应的情况是指鼠标拖拽选择时是从前向后,还是从后向前,又或者是双击选中。
insertEmojiText (name) {
let input = this.$refs.formInput;
let emojiText = `[${name}]`;
input.focus();
input.setRangeText(emojiText, input.selectionStart, input.selectionEnd, "end");
input.blur();
}
退格键支持 - 以表情符号为整体删除文本
handleFormInputKeydown (event) {
let input = this.$refs.formInput;
let chatString = input.value;
// "Backspace" and selection type "Caret"
if (event.keyCode === 8 && input.selectionStart === input.selectionEnd) {
let indexEnd = input.selectionStart - 1;
let charToDelete = chatString.charAt(indexEnd);
// delete the whole [***]
if (charToDelete === "]") {
event.preventDefault();
let indexStart = chatString.lastIndexOf("[", indexEnd);
input.setRangeText("", indexStart, indexEnd + 1, "end");
}
}
}
完整代码示例
微博风格(表情图和文字一起) https://codesandbox.io/s/emoji-input-contenteditable-75qe8 微信风格(表情用纯文本符号替代) https://codesandbox.io/s/emoji-input-text-yqfe3
补充
光标颜色
input {
caret-color: red;
}
输入法里的表情字符
定义虚拟键盘的动作键
<div
ref="inputBox"
enterkeyhint="send"
contenteditable="true"></div>
结语
评论
Audiorecognizershazam 算法在 Java 中的实现
Audiorecognizer是shazam算法在Java中的实现。shazam主要应用于基于指纹的音乐检索。Audiorecognizer可以很精准的识别上10种来自本地的或者网络的不同的MP3文件
Audiorecognizershazam 算法在 Java 中的实现
0
Audiorecognizershazam 算法在 Java 中的实现
Audiorecognizer 是 shazam 算法在 Java 中的实现。shazam主要应用于
Audiorecognizershazam 算法在 Java 中的实现
0
react-desktopReact 实现的 Web 桌面
一个使用react编写的web桌面。使用typescript来编写逻辑,react来编写view,j
react-desktopReact 实现的 Web 桌面
0
react-desktopReact 实现的 Web 桌面
一个使用react编写的web桌面。使用typescript来编写逻辑,react来编写view,jade写基本的dom结构,打包工具使用webpack。运行效果:准备npm update -gnpm
react-desktopReact 实现的 Web 桌面
0