最近写博客需要插入一些截图,想着用DataURL会方便点,于是需要一个把图片转成DataURL的工具。搜索一番后发现这个功能用HTML就能实现,通过paste事件。
先尝试在Chrome上实现,Chrome版本 43.0
html
<!DOCTYPE html> <html> <head></head> <body> <textarea id="result" style="800px; height:600px; resize:none"></textarea> <script> var body = document.getElementsByTagName('body')[0]; body.addEventListener('paste', function(e){ var clipboard = e.clipboardData; var type = clipboard.items[0].type; if (type.match(/image/)) { var blob = clipboard.items[0].getAsFile(); var file = new FileReader(); file.addEventListener('loadend', function(e){ document.getElementById('result').value = e.target.result; }); file.readAsDataURL(blob); } else { document.getElementById('result').value = "not an image type: " + type + " "; } }); </script> </body> </html>
给body添加一个paste事件,会在粘贴时触发,粘贴有关的信息都会随着e传入回调函数。e是一个ClipboardEvent,获取它的clipboardData,就可以通过一系列操作取出数据。
首先检查一下粘贴数据的类型,如果是图片则取出Blob对象,再用FileReader去读取,结果就是DataURL了。
如果不是图片,直接打印提示信息。
粘贴一段文本的效果:
这里需要注意的是,paste是在粘贴前触发的,所以文本会在提示信息打印后被粘贴到文本框里(粘贴的默认行为)。如果需要取消这种默认行为,可以用 e.preventDefault()
。
Chrome的代码在IE上完全无法工作,然后我找到了一个微软IE的粘贴图片的演示。
这个演示很有意思,IE可以直接在“编辑器”里粘贴图片,而且这是由浏览器支持的,甚至不需要Javascript。
给div设置一个contenteditable属性之后,这个div就可以被任意编辑,在其中粘贴的图片会自动通过img标签显示,它的src就是我们要的DataURL,直接获取就可以了。
这个演示需要IE11(Edge),以下我写的也一样。
html
<!DOCTYPE html> <html> <body> <textarea id="result" style="800px; height:600px; resize:none"></textarea> <div id="editor" contenteditable="true" style="border:1px solid #ccc"> paste here </div> </body> <script> var editor = document.getElementById('editor'); editor.addEventListener('paste', function(e){ console.log(e); setTimeout("updateDivContent()", 0); }); function updateDivContent(){ for (var i=0;i<editor.childNodes.length;i++) { var node = editor.childNodes[i]; if(node.nodeName == "IMG"){ result = node.src; } } for (var i=0;i<editor.childNodes.length;i++) { editor.removeChild(editor.childNodes[i]); } document.getElementById('result').value = result; } </script> </html>
这里传给paste回调的e实际上是个DragEvent,不过它没有包含粘贴的数据(dataTransfer是null),所以并没有什么用。
如果在回调里获取不到粘贴的数据,我们便需要在粘贴结束后,再去获取div里的img标签,因为粘贴的行为是在回调之后执行的。
这里我通过setTimeout实现在粘贴后执行函数,这种做法看上去很不靠谱(我不知道),不过微软那个例子里也有类似的写法。
在updateDivContent里,先获取img的src,然后清空div,再设置textarea来显示DataURL。
实际上呢IE这个例子有点舍本逐末的感觉,既然浏览器支持这样的特性,可以把div直接做成一个编辑器,这样就更方便了。
最后有一个疑问是,微软的例子里的Blob String到底是什么机制?看上去是把图片保存到了本地的某个位置,再用那一串字符串去索引?