资讯专栏INFORMATION COLUMN

【在网页中获取截图数据】Chrome和Firefox下的实战经验

vslam / 1685人阅读

摘要:最近在实现一个功能,需求如下前提当前页面无弹窗页面任意位置执行粘贴读取剪切板中的截屏数据上传截图首先还是从网上找相关的例子。找到了上的专栏文章获取剪切板内容,控制图片粘贴。

最近在实现一个功能,需求如下:

前提:当前页面无弹窗

页面任意位置执行粘贴

读取剪切板中的截屏数据

上传截图

首先还是从网上找相关的例子。

找到了SF上的专栏文章《js获取剪切板内容,js控制图片粘贴》。

于是基于这个,做出了第一版的截图上传功能。

由于项目使用的是angularjs,事先已经封装好一套上传图片的办法,只需要调用 $scope.image = blob,自动就会发送、上传该文件。

我是半路介入项目的。原来为数不多的几个js文件实在太大,一个apiService.js就累积了三四千行,各种服务都在这个文件里,主视图就一个mainController,也是三四千行。

说实话,我真的惊呆了。

所以还是尽量避免修改原来的代码。

按照我自己习惯,把功能封装成directive,独立建一个文件。

代码如下:(特别鸣谢本期节目的文章)

</>复制代码

  1. /**
  2. * @description: 截屏上传
  3. * @author: angusfu1126@qq.com
  4. * @date: 2016-03-03 20:59:09
  5. */
  6. app.directive("screenshotOrDragUpload", /*ngInject*/ function($filter) {
  7. return {
  8. restrict: "A"
  9. link: function($scope, iElm, iAttrs, controller) {
  10. var imageRegex = /^image//i;
  11. // 粘贴截图事件
  12. document.addEventListener("paste", onPasteHandler, false);
  13. // 作用域销毁的时候解除事件绑定
  14. $scope.$on("$destroy", function() {
  15. document.removeEventListener("paste", onPasteHandler);
  16. });
  17. /**
  18. * 全局蒙版显示的时候
  19. * 不执行粘贴或者拖拽功能
  20. * 避免和各种弹层ng-show条件太耦合
  21. * 此处使用DOM方法判断
  22. */
  23. function isMaskShown() {
  24. // 项目依赖于jquery
  25. return angular.element(".global-mask").is(":visible");
  26. }
  27. /**
  28. * 根据时间戳命名
  29. */
  30. function generateFileName(user) {
  31. return $filter("date")(new Date(), "yyyyMMdd_HH:MM:ss");
  32. }
  33. /**
  34. * 处理 `ctrl + v` 截图粘贴事件
  35. */
  36. function onPasteHandler(e) {
  37. if (isMaskShown()) return;
  38. var clipboardData = e.clipboardData;
  39. var ua = window.navigator.userAgent;
  40. // 如果无法获取剪贴板则返回
  41. if (!clipboardData || !clipboardData.items) {
  42. return;
  43. }
  44. // Mac平台下Chrome49版本以下
  45. // 复制Finder中的文件的Bug Hack掉
  46. // see: https://segmentfault.com/a/1190000004288686
  47. if (clipboardData.items
  48. && clipboardData.items.length === 2
  49. && clipboardData.items[0].kind === "string"
  50. && clipboardData.items[1].kind === "file"
  51. && clipboardData.types
  52. && clipboardData.types.length === 2
  53. && clipboardData.types[0] === "text/plain"
  54. && clipboardData.types[1] === "Files"
  55. && ua.match(/Macintosh/i)
  56. && Number(ua.match(/Chrome/(d{2})/i)[1]) < 49
  57. ) {
  58. return;
  59. }
  60. var len = clipboardData.items.length,
  61. item = null,
  62. blob = null;
  63. while (len--) {
  64. item = clipboardData.items[len];
  65. if (item.kind == "file") {
  66. blob = item.getAsFile();
  67. if (imageRegex.test(blob.type) && blob.size > 0) {
  68. blob.name = generateFileName();
  69. // 调用上传
  70. $scope.image = blob;
  71. break;
  72. }
  73. }
  74. }
  75. }
  76. }
  77. };
  78. });

当然,文章不可能就此结束。。。

分割线休息片刻

==============================================================

上述功能只有在Chrome和Safari中有效,但到火狐上面就挂掉了啊。。。

测试一下,给document绑定paste事件,粘贴的时候压根就读不到数据。

火狐下面,并没有clipboardData.items这一项。

o(╯□╰)o

那怎么办呢?

只能退而求其次。放弃,或者寻求降级的办法。

就在我觉得无路可走的时候,火狐的一个特点让我眼前一亮。。。

分别用chrome和firefox打开这个demo试试看,试着用qq截个图或者在文件夹中复制一张图片,粘贴在红色框框里。

有没有发现,只有在火狐下能把图粘贴进来?

嗯,解决办法就在这里了。

其实,demo中的红色框框是一个有contenteditable属性的div

关于contenteditable,此处有张鑫旭大神的博文两篇,且记在此处备忘:

小tip: 如何让contenteditable元素只能输入纯文本

div模拟textarea文本域轻松实现高度自适应

firefox下面,是可以把剪切板中的图片数据粘贴进去的,而chrome下面则不行了。

而项目的输入框,正好是一个pre标签加上contenteditable属性模拟出来的。完美~~~(此处应有金星老师表情包)

好了,在火狐中粘贴截图之后,右键查看一下,是不是像下图酱紫的?

有木有看到醒目的img标签?

有木有看到醒目的data:image/png;base64,

办法有了。解决方案如下:

监听keydown事件

检测输入框是否为空

非空:不允许粘贴图片(但我们不能事先判断数据类型,只能迅速remove掉img元素)

空的:获取img元素及其src数据,然后迅速移除元素

当然,此处是有坑的。。。

具体坑在哪里呢?看代码吧。其实我觉得我可能没完全解决。

</>复制代码

  1. if (/firefox/i.test(navigator.userAgent)) {
  2. var URL = (window.URL || window.mozURL),
  3. supportTransform = URL && window.Blob && window.atob && window.ArrayBuffer && window.Uint8Array,
  4. // see http://jsperf.com/blob-base64-conversion
  5. convertBase64UrlToBlob = function(urlData) {
  6. //去掉url的头,并转换为byte
  7. var bytes = window.atob(urlData.split(",")[1]);
  8. //处理异常,将ascii码小于0的转换为大于0
  9. var ab = new ArrayBuffer(bytes.length);
  10. var ia = new Uint8Array(ab);
  11. for (var i = 0; i < bytes.length; i++) {
  12. ia[i] = bytes.charCodeAt(i);
  13. }
  14. return new Blob([ab], {
  15. type: "image/png"
  16. });
  17. };
  18. $("pre").on("keydown", function(e) {
  19. var isCtrlV = (e.ctrlKey && e.keyCode == "86");
  20. if (!supportTransform || !isCtrlV) return;
  21. var $this = $(this),
  22. html = $this.html(),
  23. canPasteImage = false;
  24. // Notice
  25. // 火狐的坑在这里啊啊啊啊
  26. // 只有空的时候才能粘贴图片
  27. if (!html || html === "
    ") {
  28. canPasteImage = true;
  29. }
  30. setTimeout(function() {
  31. var $imgs = $this.find("img").remove(),
  32. data = $imgs.eq(0).attr("src");
  33. if (canPasteImage && data) {
  34. var blob = convertBase64UrlToBlob(data);
  35. blob.name = generateFileName();
  36. // 调用上传
  37. $scope.image = blob;
  38. }
  39. }, 0);
  40. });
  41. }

做个笔记: Blob对象和base64字符串的转换, http://jsperf.com/blob-base64-conversion

目前还没在IE上测试过,不知道结果如何。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/78872.html

相关文章

  • 【踩坑】近来Firefox上遇到的一些坑

    摘要:最近在帮人解决下的一些兼容问题。验证不通过的话,输入框会加上红色的边框。然后妹纸在描述中说的是浏览器中,修改密码页面,输入框中不输入任何字符,输入框颜色也是红的我还以为又是哪里的写得不对呢。最后发现,输入框好像都带了个属性。 因为工作一年多以来,做的工作基本都是和webkit系列打交道。 先是做m站,后来做了两个app内嵌的hybrid项目,从来只考虑webkit前缀和相关的伪类。 最...

    JaysonWang 评论0 收藏0
  • 【踩坑】近来Firefox上遇到的一些坑

    摘要:最近在帮人解决下的一些兼容问题。验证不通过的话,输入框会加上红色的边框。然后妹纸在描述中说的是浏览器中,修改密码页面,输入框中不输入任何字符,输入框颜色也是红的我还以为又是哪里的写得不对呢。最后发现,输入框好像都带了个属性。 因为工作一年多以来,做的工作基本都是和webkit系列打交道。 先是做m站,后来做了两个app内嵌的hybrid项目,从来只考虑webkit前缀和相关的伪类。 最...

    AJie 评论0 收藏0
  • 摆脱客户端?网页发起直播势必行!

    摘要:背景近几年直播行业飞速发展,但是由于端这方面功能的长时间缺失,使得直播端以客户端为主的出现使得网页也可以成为直播端。通过发送消息到插件调起屏幕共享。的点对点连接的过程为呼叫端给接收端发送一个信息。下面简单介绍下使用声网发起直播的流程。 背景 近几年直播行业飞速发展,但是由于Web端这方面功能的长时间缺失,使得直播端以客户端为主;WebRTC 的出现使得网页也可以成为直播端。那么究竟We...

    econi 评论0 收藏0
  • 【Python爬虫】4万字,详解selenium从入门到实战【错过再无】

    摘要:难在哪里根据上面的标签需要定位最后一行标签,以下列出了四种方式,定位的方式多样并不唯一,使用时根据情况进行解析即可。加入每日一练我们使用并指明标签内全部文本即可定位。 ...

    shiyang6017 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<