这个事情怎么说呢,我前不久弄了个 Markdown 邮件在线编辑器,可是有个小伙伴给我提了一个需求:能不能再把邮件转回 Markdown 呢?于是我就一直想完善这一功能,想要实现这一功能首先我们得先获取到粘贴的 html 吧,但是我试了试直接粘贴到 textarea 里面就会变成纯文本的,咦,这就很神奇了。
那么 QQ 邮箱是怎么实现的呢?通过多番打探,终于发现这个神奇的玩意 textarea 的粘贴事件,通过这东西我们就能获取到 html 格式的粘贴文本,我们瞧瞧代码
var editableDiv = document.getElementById('textarea_id');
// 获取编辑框对象
function handlepaste (e) {
var types, pastedData, savedContent;
// Browsers that support the 'text/html' type in the Clipboard API (Chrome, Firefox 22+)
if (e && e.clipboardData && e.clipboardData.types && e.clipboardData.getData) {
// 在类型列表中检查 "text/html"
// 需要 DOMStringList 位,我们不需要处理 'text/plain' 的内容,直接返回就好了
// Safari/Edge 也是直接返回就好了
types = e.clipboardData.types;
if (((types instanceof DOMStringList) && types.contains("text/html")) || (types.indexOf && types.indexOf('text/html') !== -1)) {
// 提取数据并将其传递给回调
pastedData = e.clipboardData.getData('text/html');
processPaste(editableDiv, pastedData);
// 停止实际粘贴数据
e.stopPropagation();
e.preventDefault();
return false;
}
}
// 将现有元素内容移动到 DocumentFragment 以便保存数据
savedContent = document.createDocumentFragment();
while(editableDiv.childNodes.length > 0) {
savedContent.appendChild(editableDiv.childNodes[0]);
}
// 等待浏览器将内容粘贴到其中并进行清理
waitForPastedData(editableDiv, savedContent);
return true;
}
function waitForPastedData (elem, savedContent) {
// 数据已由浏览器处理,对其进行处理
if (elem.childNodes && elem.childNodes.length > 0) {
// 通过 innerHTML 检索粘贴的内容
// 或者在这里循环遍历 elem.childNodes 或 elem.getElementsByTagName
var pastedData = elem.innerHTML;
// 恢复保存的内容
elem.innerHTML = "";
elem.appendChild(savedContent);
// 跳转返回数据
processPaste(elem, pastedData);
}
// 等待20毫秒再试一次
else {
setTimeout(function () {
waitForPastedData(elem, savedContent)
}, 20);
}
}
function processPaste (elem, pastedData) {
// 取到粘贴的 Html 数据为 pastedData
console.log(pastedData);
}
if (editableDiv.addEventListener) {
editableDiv.addEventListener('paste', handlepaste, false);
// 现代浏览器,注意:Firefox <= 6 需要第3个参数
} else {
editableDiv.attachEvent('onpaste', handlepaste);
// IE <= 8
}
简单介绍
processpaste
的 processpaste
事件附加了 types
函数并传递了一个参数:粘贴事件的 DOMStringList
对象。 我们特别感兴趣的是此事件的 contains
属性,它允许在非浏览器中进行剪贴板访问。 在IE中,等效的是 indexOf
。尽管这有一个稍微不同的API,请参阅下面的资源部分
processpaste 这个功能有两个分支,首先检查是否存在 processpaste
并检查它的 types
属性是否包含'text / html'( types
可以是使用 contains
方法检查的 DOMStringList
,也可以是使用 indexOf
方法检查的字符串)。 如果满足所有这些条件,那么我们按照解决方案继续,除了 'text / html' 而不是 'text / plain' 。 目前适用于 Chrome 和 Firefox 22+ 。
如果不支持此方法的其他浏览器 ,那么我们可以将元素的内容保存到 processpaste
或者清空元素
waitForPastedData 此函数首先轮询粘贴的数据(每20ms一次),这是必要的,因为它不会立即显示。 当数据出现时:先将可 textarea(现在是粘贴数据)的 innerHTML 保存到变量中,然后恢复 DocumentFragment 中保存的内容再使用检索到的数据调用 ' processPaste ' 函数
processPaste 方法使用粘贴的数据做任意事情。 在这种情况下,我只是打印数据,你可以做任何你喜欢的事情。 您可能希望通过某种数据清理过程运行粘贴的数据。
保存并恢复光标位置,在实际情况下,你可能希望在之前保存选择,然后将其恢复(在 textarea 上设置光标位置)。 然后,你可以在用户启动粘贴操作时将粘贴的数据插入光标所在的位置