Web聊天工具的富文本输入框
最近折腾 Websocket,打算开发一个聊天室应用练练手。在应用开发的过程中发现可以插入 emoji ,粘贴图片的富文本输入框其实蕴含着许多有趣的知识,于是便打算记录下来和大家分享。
首先来看看 demo 效果:
是不是觉得很神奇?接下来我会一步步讲解这里面的功能都是如何实现的。
输入框富文本化
传统的输入框都是使用 来制作的,它的优势是非常简单,但最大的缺陷却是无法展示图片。为了能够让输入框能够展示图片(富文本化),我们可以采用设置了 contenteditable="true" 属性的
简单创建一个 index.html 文件,然后写入如下内容:
打开浏览器,就能看到一个默认已经带了一张图片的输入框:
光标可以在图片前后移动,同时也可以输入内容,甚至通过退格键删除这张图片——换句话说,图片也是可编辑内容的一部分,也意味着输入框的富文本化已经体现出来了。
接下来的任务,就是思考如何直接通过 control + v 把图片粘贴进去了。
处理粘贴事件
任何通过“复制”或者 control + c 所复制的内容(包括屏幕截图)都会储存在剪贴板,在粘贴的时候可以在输入框的 onpaste 事件里面监听到。
document.querySelector('.editor').addEventListener('paste', (e) => {
console.log(e.clipboardData.items)
})
而剪贴板的的内容则存放在 DataTransferItemList 对象中,可以通过 e.clipboardData.items 访问到:
细心的读者会发现,如果直接在控制台点开 DataTransferItemList 前的小箭头,会发现对象的 length 属性为0。说好的剪贴板内容呢?其实这是 Chrome 调试的一个小坑。在开发者工具里面,console.log 出来的对象是一个引用,会随着原始数据的改变而改变。由于剪贴板的数据已经被“粘贴”进输入框了,所以展开小箭头以后看到的 DataTransferItemList 就变成空的了。为此,我们可以改用 console.table 来展示实时的结果。
在明白了剪贴板数据的存放位置以后,就可以编写代码来处理它们了。由于我们的富文本输入框比较简单,所以只需要处理两类数据即可,其一是普通的文本类型数据,包括 emoji 表情;其二则是图片类型数据。
新建 paste.js 文件:
const onPaste = (e) => {
// 如果剪贴板没有数据则直接返回
if (!(e.clipboardData && e.clipboardData.items)) {
return
}
// 用Promise封装便于将来使用
return new Promise((resolve, reject) => {
// 复制的内容在剪贴板里位置不确定,所以通过遍历来保证数据准确
for (let i = 0, len = e.clipboardData.items.length; i < len; i++) {
const item = e.clipboard