最近在完成一个功用,需求以下:
前提:当前页面无弹窗
页面恣意位置实行粘贴
读取剪切板中的截屏数据
上传截图
起首照样从网上找相干的例子。
找到了SF上的专栏文章《js猎取剪切板内容,js掌握图片粘贴》。
因而基于这个,做出了初版的截图上传功用。
因为项目运用的是angularjs,事前已封装好一套上传图片的要领,只需要挪用 $scope.image = blob
,自动就会发送、上传该文件。
我是半路参与项目的。本来为数不多的几个js文件着实太大,一个apiService.js
就积累了三四千行,种种效劳都在这个文件里,主视图就一个mainController,也是三四千行。
说实话,我真的惊呆了。
所以照样只管防止修正本来的代码。
依据我本身习气,把功用封装成directive
,自力建一个文件。
代码以下:(迥殊道谢本期节目的文章)
/**
* @description: 截屏上传
* @author: angusfu1126@qq.com
* @date: 2016-03-03 20:59:09
*/
app.directive('screenshotOrDragUpload', /*ngInject*/ function($filter) {
return {
restrict: 'A'
link: function($scope, iElm, iAttrs, controller) {
var imageRegex = /^image\//i;
// 粘贴截图事宜
document.addEventListener('paste', onPasteHandler, false);
// 作用域烧毁的时刻消除事宜绑定
$scope.$on('$destroy', function() {
document.removeEventListener('paste', onPasteHandler);
});
/**
* 全局蒙版显现的时刻
* 不实行粘贴或许拖拽功用
* 防止和种种弹层ng-show前提太耦合
* 此处运用DOM要领推断
*/
function isMaskShown() {
// 项目依赖于jquery
return angular.element('.global-mask').is(':visible');
}
/**
* 依据时候戳定名
*/
function generateFileName(user) {
return $filter('date')(new Date(), 'yyyyMMdd_HH:MM:ss');
}
/**
* 处置惩罚 `ctrl + v` 截图粘贴事宜
*/
function onPasteHandler(e) {
if (isMaskShown()) return;
var clipboardData = e.clipboardData;
var ua = window.navigator.userAgent;
// 假如没法猎取剪贴板则返回
if (!clipboardData || !clipboardData.items) {
return;
}
// Mac平台下Chrome49版本以下
// 复制Finder中的文件的Bug Hack掉
// see: https://segmentfault.com/a/1190000004288686
if (clipboardData.items
&& clipboardData.items.length === 2
&& clipboardData.items[0].kind === "string"
&& clipboardData.items[1].kind === "file"
&& clipboardData.types
&& clipboardData.types.length === 2
&& clipboardData.types[0] === "text/plain"
&& clipboardData.types[1] === "Files"
&& ua.match(/Macintosh/i)
&& Number(ua.match(/Chrome\/(\d{2})/i)[1]) < 49
) {
return;
}
var len = clipboardData.items.length,
item = null,
blob = null;
while (len--) {
item = clipboardData.items[len];
if (item.kind == "file") {
blob = item.getAsFile();
if (imageRegex.test(blob.type) && blob.size > 0) {
blob.name = generateFileName();
// 挪用上传
$scope.image = blob;
break;
}
}
}
}
}
};
});
固然,文章不能够就此结束。。。
分割线歇息少焉
==============================================================
上述功用只要在Chrome和Safari中有用,但到火狐上面就挂掉了啊。。。
测试一下,给document绑定paste事宜,粘贴的时刻压根就读不到数据。
火狐下面,并没有clipboardData.items
这一项。
o(╯□╰)o
那怎么办呢?
只能退而求其次。摒弃,或许追求降级的要领。
就在我以为无路可走的时刻,火狐的一个特性让我眼前一亮。。。
分别用chrome和firefox翻开这个demo碰运气,试着用qq截个图或许在文件夹中复制一张图片,粘贴在赤色框框里。
有无发明,只要在火狐下能把图粘贴进来?
嗯,处理要领就在这里了。
实在,demo中的赤色框框是一个有contenteditable
属性的div
。
关于contenteditable
,此处有张鑫旭大神的博文两篇,且记在此处备忘:
firefox下面,是能够把剪切板中的图片数据粘贴进去的,而chrome下面则不行了。
而项目的输入框,正好是一个pre
标签加上contenteditable
属性模仿出来的。圆满~~~(此处应有金星先生脸色包)
好了,在火狐中粘贴截图以后,右键检察一下,是不是是像下图酱紫的?
有木有看到能干的img
标签?
有木有看到能干的data:image/png;base64,
?
要领有了。处理方案以下:
监听
keydown
事宜检测输入框是不是为空
非空:不允许粘贴图片(但我们不能事前推断数据类型,只能敏捷remove掉img元素)
空的:猎取img元素及其src数据,然后敏捷移除元素
固然,此处是有坑的。。。
详细坑在那里呢?看代码吧。实在我以为我能够没完整处理。
if (/firefox/i.test(navigator.userAgent)) {
var URL = (window.URL || window.mozURL),
supportTransform = URL && window.Blob && window.atob && window.ArrayBuffer && window.Uint8Array,
// see http://jsperf.com/blob-base64-conversion
convertBase64UrlToBlob = function(urlData) {
//去掉url的头,并转换为byte
var bytes = window.atob(urlData.split(',')[1]);
//处置惩罚非常,将ascii码小于0的转换为大于0
var ab = new ArrayBuffer(bytes.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < bytes.length; i++) {
ia[i] = bytes.charCodeAt(i);
}
return new Blob([ab], {
type: 'image/png'
});
};
$('pre').on('keydown', function(e) {
var isCtrlV = (e.ctrlKey && e.keyCode == '86');
if (!supportTransform || !isCtrlV) return;
var $this = $(this),
html = $this.html(),
canPasteImage = false;
// Notice
// 火狐的坑在这里啊啊啊啊
// 只要空的时刻才粘贴图片
if (!html || html === '<br>') {
canPasteImage = true;
}
setTimeout(function() {
var $imgs = $this.find('img').remove(),
data = $imgs.eq(0).attr('src');
if (canPasteImage && data) {
var blob = convertBase64UrlToBlob(data);
blob.name = generateFileName();
// 挪用上传
$scope.image = blob;
}
}, 0);
});
}
做个笔记: Blob对象和base64字符串的转换, http://jsperf.com/blob-base64-conversion
现在还没在IE上测试过,不知道效果怎样。