【在网页中获取截图数据】Chrome和Firefox下的实战经验
【转载自我在segmentfault的专栏:https://segmentfault.com/a/1190000004584071】
最近在实现一个功能,需求如下:
前提:当前页面无弹窗
页面任意位置执行粘贴
读取剪切板中的截屏数据
上传截图
首先还是从网上找相关的例子。
找到了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上测试过,不知道结果如何。
以上。
谢谢阅读。
如蒙您收藏、推荐一下,那自然是极好的了。
【在网页中获取截图数据】Chrome和Firefox下的实战经验的更多相关文章
- WebClient HttpWebRequest从网页中获取请求数据
WebClient HttpWebRequest //HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(urlAddress) ...
- 使用Xpath从网页中获取数据
/// <summary> /// 从官方网站中抓取产品信息存放在本地数据库中 /// </summary> /// <returns></returns&g ...
- 浅谈如何使用python抓取网页中的动态数据
我们经常会发现网页中的许多数据并不是写死在HTML中的,而是通过js动态载入的.所以也就引出了什么是动态数据的概念, 动态数据在这里指的是网页中由Javascript动态生成的页面内容,是在页面加载到 ...
- python抓取网页中的动态数据
一.概念 网页中的许多数据并不是写死在HTML中的,而是通过js动态载入的.所以也就引出了什么是动态数据的概念,动态数据在这里指的是网页中由Javascript动态生成的页面内容,是在页面加载到浏览器 ...
- 解决网页中Waiting (TTFB)数据加载过慢的问题
解决网页中Waiting (TTFB)数据加载过慢的问题 最近做了一个网页,在本地测试良好,数据可以得到很快的反馈,但是当部署到云端Linux上时候,就会出现加载缓慢的问题.本地测试,得到数据大概3s ...
- IOS从视频中获取截图
从视频中获取截图: NSString *movpath =[[NSBundle mainBundle] pathForResource:@”iosxcode4″ ofType:@”mov”]; mpv ...
- 通过DialogFragment从DatePicker或TimePicker中获取日期数据
通过DialogFragment从DatePicker或TimePicker中获取日期数据 一个activity类,里面存有date和time的变量,想通过dialogfragment的方式获取用户输 ...
- Android中获取网络数据时的分页加载
//此实在Fragment中实现的,黄色部分为自动加载,红色部分是需要注意的和手动加载, 蓝色部分是睡眠时间,自我感觉不用写 ,还有就是手动加载时,不知道为什么进去后显示的就是最后一行,求大神 ...
- android开发中获取<meta-data>数据
在 AndroidManifest.xml 中,<meta-data>元素是一个键值对,往往被包含在<application> .<activity>.<se ...
随机推荐
- windows系统中的dll的作用详细解释
什么是.DLL文件? DLL 是一个包含可由多个程序同时使用的代码和数据的库.例如,在 Windows 操作系统中,Comdlg32 DLL 执行与对话框有关的常见函数.因此,每个程序都可以使用该 D ...
- Android 电源系列小结s
package com.ritterliu.newBatteryWidget; import android.app.Activity; import android.app.Service; imp ...
- ue中替换行
把替换的字符替换为^p 如:123,12,3,1, 在UE力把“,”替换未“^p”,就会替换为 1231231
- 去掉iphone 的圆角样式
每次面对iphone这种丑丑的样式,我简直不能再愉快的写代码~~而且每次记不住那烦人的属性~~~必须记录下来~~ -webkit-appearance:none 为了下次不用再百度,终于背下来~~~
- codevs 1183 泥泞的道路 01分数规划
题目链接 题目描述 Description CS有n个小区,并且任意小区之间都有两条单向道路(a到b,b到a)相连.因为最近下了很多暴雨,很多道路都被淹了,不同的道路泥泞程度不同.小A经过对近期天气和 ...
- System timers granularity
http://code.google.com/p/javasimon/wiki/SystemTimersGranularity
- Visual Studio 中用管理员权限运行、调试程序
原文:Visual Studio 中用管理员权限运行.调试程序 一个Sample小程序,用于验证WoW64的Windows Registry的读写访问.在Visual Studio 2010中调试运行 ...
- png图片压缩优化
1.2 软件环境 软件名称:Opting下载地址: http://optipng.sourceforge.net/ 安装版本:0.7.5安装位置:/apps/svr/opting 安装可能遇到的问题: ...
- BZOJ 2253: [2010 Beijing wc]纸箱堆叠
题目 2253: [2010 Beijing wc]纸箱堆叠 Time Limit: 30 Sec Memory Limit: 256 MBSubmit: 239 Solved: 94 Descr ...
- Linux-NGINX 能否添加P3P头,如何添加。 - 德问:编程社交问答
Linux-NGINX 能否添加P3P头,如何添加. - 德问:编程社交问答 您的投票让 杜鑫 声誉值增加5分. 支持投票,不仅能让提问用户获得声誉值,让好的问题有更多的曝光,更能帮助社区筛选出好 ...