使用Javascript获取剪贴板图片的DataURL

602 查看

最近写博客需要插入一些截图,想着用DataURL会方便点,于是需要一个把图片转成DataURL的工具。搜索一番后发现这个功能用HTML就能实现,通过paste事件。


先尝试在Chrome上实现,Chrome版本 43.0

html<!DOCTYPE html>
<html>
<head></head>
<body>
    <textarea id="result" style="width: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\ntype: " + type + "\n\n";
            }
        });
    </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="width: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到底是什么机制?看上去是把图片保存到了本地的某个位置,再用那一串字符串去索引?