前言

  1. 首先做个自我介绍,我是成都某企业的一名刚刚入行约一年的前端,在之前的开发过程中,遇到了问题,也解决了问题,
    但是在下一次解决相同问题的时候,只对这个问题有一丝丝的印象,还需要从新去查找,于是,我注册了segmemtfault
    便于搜集我的问题总结,以及将踩坑经验分享给每一个开发人员,好了,闲话不多说。

需求

  1. 需求:要求能够实现根据后端返回的数据生成一张image,便于用户将图片分享到朋友或者朋友圈,取得用户的关注。

开始踩坑

一.html2canvas对于跨域图片,转换的时候会将跨域图片识别为空白。
问题分析:
既然是由于跨域引起的问题,那我们让资源不跨域不就可以访问了吗?
解决办法:
将图片放置服务器,通过nginx进行代理资源,前端访问图片便不涉及到跨域问题。

二.html2canvas动态加载内容,通过canvas转换出来的数据,图片为空
问题分析:
内容是动态加载进来的,转换肯定是在请求完毕之后再去转换,但是在请求完毕之后去转换,按理说所需要的所有数据都已经到达前端,应该可以转换,经过思考,发现图片内容从后台读取需要一定时间去解析,才能够完整的将图片资源展示出来,html2canvas是将页面上显示的dom元素,经过解析将dom画在canvas上在转换为image图片格式。
解决办法:
1.让html2canvas转换代码等待一定时间,在进行转换操作,可进行转换。代码如下图所示

2.当全部的图片数据都加载完毕之后,在执行转换操作。(本人建议第二种,更保险)

三.html2canvas转换的base64位图不能被ios8以上版本所识别。会呈现出整个截图页面空白
问题分析:
这个问题的起因,应该是html2canvas对高版本的ios不支持(自我感觉),这个问题我很是头疼,当时根本没有对ios进行测试。客户使用的时候发现了这个问题,没法。想办法解决。百度说是由于ios不能识别base64的前缀,于是我试过将图片的前缀去除,但发现没反应。还是无用。思来想去感觉html2canvas坑太多了。填都填不完。于是。
解决办法:
我采用了另一款插件,dom-to-image,弄上去没有问题了。

四.dom-to-image运用上去,在ios上能够出现内容了,但发现存在一个问题,部分图片内容,第一次进行公众号网页加载,没有正确显示,要在次进入才会显示,此bug同样是ios8以上版本
问题分析:
这一个问题我没有找到问题所在,一脸懵,不过最终还是得到了解决。
解决办法:
运用dom-to-imagede toSvg方式完美解决问题。

五.离成功只有一步之遥了,使用了svg之后安卓手机不能将图片分享给朋友。识别不了
问题分析:
安卓能识别jpeg但不能识别svg矢量图片
解决办法:
自己手写咯。判断手机为安卓还是ios。

六.所有的问题都已解决,我兴奋的跑去借了个果5,拿来测试,发现网页的背景图片不见了。
问题分析:
我长按两秒左右又是正常显示了,故图片是已经完美转换成功,可能是因为图片在转换过程中,没有完美适配到4.0寸的屏幕,
解决办法:
模拟长按事件,解决bug,这个方式可能不太好,但也是一种解决方式。

总结

躺过的坑都是我的经验,分享的同时我又加固了一遍。解决实际问题的思路,在过了一遍,对我帮助很棒。

代码参考

  1. //判断手机为安卓还是ios 安卓html2canvas方法 ios系统dom-to-image方法
  2. $(".code").click(function() {
  3. var u = navigator.userAgent;
  4. var isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
  5. var isAndroid = u.indexOf('Android') > - || u.indexOf('Adr') > -; //android终端
  6. if(isiOS) {
  7. window.location.href = "mycodeios.html"
  8. } else if(isAndroid) {
  9. window.location.href = "mycode.html"
  10. }
  11. })

安卓html2canvas方法

  1. <!DOCTYPE html>
  2. <html lang="zh">
  3.  
  4. <head>
  5. <meta charset="UTF-8" />
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  7. <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  8. <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
  9. <title>分享</title>
  10. <link rel="stylesheet" type="text/css" href="css/reset.css" />
  11. <style type="text/css">
  12. /*头部*/
  13.  
  14. body {
  15. background: #FFFFFF;
  16. height: !important;
  17. }
  18.  
  19. .container {
  20. max-width: 750px;
  21. min-width: 32px;
  22. margin: auto;
  23. background: #FFFFFF;
  24. }
  25.  
  26. .zhe {
  27. position: fixed;
  28. max-width: 750px;
  29. min-width: 32px;
  30. width: %;
  31. height: %;
  32. background: #45A196;
  33. z-index: ;
  34. }
  35.  
  36. .imge {
  37. position: absolute;
  38. max-width: 750px;
  39. min-width: 32px;
  40. width: %;
  41. height: %;
  42. margin: % %;
  43. z-index: ;
  44. /*background: url(codeimg/code.jpg) no-repeat;*/
  45. /*background-size: contain;*/
  46. }
  47.  
  48. .left {
  49. position: absolute;
  50. left: %;
  51. top: %;
  52. color: #FFFFFF;
  53. font-size: 26px;
  54. letter-spacing: 5px;
  55. }
  56.  
  57. .bottom {
  58. position: absolute;
  59. right: %;
  60. top: %;
  61. }
  62.  
  63. .codebotom {
  64. position: absolute;
  65. padding: 10px;
  66. background: #FFFFFF;
  67. width: 90px;
  68. height: 90px;
  69. }
  70.  
  71. .butright_img {
  72. position: absolute;
  73. width: 80px;
  74. height: 80px;
  75. margin: 5px;
  76. top: 0px;
  77. left: 0px;
  78. }
  79.  
  80. .textbottom {
  81. position: absolute;
  82. width: 40px;
  83. letter-spacing: 5px;
  84. color: #FFFFFF;
  85. top: 20px;
  86. left: -45px;
  87. }
  88.  
  89. .butright {
  90. position: absolute;
  91. bottom: 50px;
  92. right: %;
  93. color: #4BA59B;
  94. padding: 10px %;
  95. border-radius: 3px;
  96. z-index: ;
  97. color: #ffffff;
  98. text-align: center;
  99. }
  100.  
  101. .image {
  102. display: block;
  103. max-width: 750px;
  104. min-width: 32px;
  105. width: %;
  106. position: absolute;
  107. top: 0px;
  108. left: 0px;
  109. background: #FFFFFF;
  110. z-index: ;
  111. }
  112. </style>
  113. </head>
  114.  
  115. <body>
  116. <div class="container">
  117. <!--二维码-->
  118. <div class="zhe"></div>
  119. <div class="imge">
  120. <div style="position: absolute; top: 0px; left: 0px;">
  121. <img src="codeimg/code.jpg" />
  122. </div>
  123. <div style="width: 100%;height: 100%; position: relative;">
  124. <div class="left state"></div>
  125. <div class="bottom">
  126. <div class="textbottom">扫码立即注册</div>
  127. <div class="codebotom">
  128. <div id="qrcode" class="butright_img"></div>
  129. </div>
  130. </div>
  131. </div>
  132. <div>
  133. <div class="butright">长按保存图片</div>
  134. </div>
  135. </div>
  136. <div class="image" style="display: block;">
  137.  
  138. </div>
  139.  
  140. </div>
  141. </body>
  142. <script src="js/config.js"></script>
  143. <script src="js/jquery-2.1.4.min.js" type="text/javascript" charset="utf-8"></script>
  144. <script src="js/fenxiang.js" type="text/javascript" charset="utf-8"></script>
  145. <script src="https://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
  146. <!--二维码-->
  147. <script src="js/jquery.qrcode.logo.min.js" type="text/javascript" charset="utf-8"></script>
  148. <!--html2canvas图片-->
  149. <script type="application/javascript" src="http://html2canvas.hertzen.com/dist/html2canvas.min.js"></script>
  150. <script type="text/javascript">
  151. // 倒计时
  152. $(function() {
  153. var openid_list = eval(decodeURIComponent(localStorage.getItem("openid")))
  154. var openid = openid_list[]
  155. var access_token = openid_list[]
  156.  
  157. window.history.pushState(null, null, "#");
  158. window.addEventListener('popstate', function(e) {
  159. window.location.href = 'my.html'
  160. }, false);
  161.  
  162. //创建二维码
  163. function createQRCode(id, url, width, height, src) {
  164. $('#' + id).empty();
  165. jQuery('#' + id).qrcode({
  166. render: 'canvas',
  167. text: url,
  168. width: width, //二维码的宽度
  169. height: height, //二维码的高度
  170. imgWidth: width / , //图片宽
  171. imgHeight: height / , //图片高
  172. src: src //图片中央的二维码
  173. });
  174. }
  175. var url = 'https://api.gzkny.com/h5/aa.html?openid=' + openid;
  176. createQRCode("qrcode", url, , , "image/follow.jpg");
  177.  
  178. // 使用html2canvas 转换html为canvas 安卓html2canvas方法
  179. function downloadForJS() {   
  180. html2canvas(document.body, {
  181. useCORS: true,
  182. logging: true
  183. }).then(function(canvas) {
  184. var imgUri = canvas.toDataURL().replace("image/png", "image/octet-stream"); // 获取生成的图片的url  
  185. // $('.zhe').hide()
  186. // $('.imge').hide()
  187. $('.image').html('<img src="' + imgUri + '"/>')
  188. });
  189. }
  190.  
  191. // 获取数据
  192. $.ajax({
  193. method: 'GET',
  194. url: window.BASE_URL + 'api/v1/member/get',
  195. contentType: 'application/x-www-form-urlencoded',
  196. async: true,
  197. dataType: "json",
  198. data: {
  199. access_token: access_token,
  200. },
  201. success: function(data) {
  202. console.log(data)
  203. if(data.error == 'success') {
  204. $('.state').html(data.data.username)
  205. downloadForJS()
  206. }
  207. }
  208. });
  209.  
  210. })
  211. </script>
  212.  
  213. </html>

ios系统dom-to-image方法(css样式一定要自己写   避免图片失效)

  1. <!DOCTYPE html>
  2. <html lang="zh">
  3.  
  4. <head>
  5. <meta charset="UTF-8" />
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  7. <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  8. <title>分享</title>
  9. <script src="js/jquery-2.1.4.min.js" type="text/javascript" charset="utf-8"></script>
  10. <script type="text/javascript" src="js/dom-to-image.js"></script>
  11. <script type="text/javascript" src="js/FileSaver.js"></script>
  12. <style type="text/css">
  13. /*头部*/
  14. * {
  15. margin: 0px;
  16. padding: 0px;
  17. }
  18.  
  19. body {
  20. background: #45A196;
  21. width: %;
  22. height: %;
  23. }
  24.  
  25. .container {
  26. max-width: 750px;
  27. min-width: 32px;
  28. margin: auto;
  29. position: relative;
  30. }
  31.  
  32. .imge {
  33. position: relative;
  34. max-width: 750px;
  35. min-width: 32px;
  36. width: %;
  37. height: %;
  38. z-index: ;
  39. }
  40.  
  41. .left {
  42. position: absolute;
  43. left: %;
  44. margin-top: %;
  45. color: #FFFFFF;
  46. font-size: 26px;
  47. letter-spacing: 5px;
  48. }
  49.  
  50. .bottom {
  51. position: absolute;
  52. }
  53.  
  54. .codebotom {
  55. position: absolute;
  56. background: #FFFFFF;
  57. width: 90px;
  58. height: 90px;
  59. }
  60.  
  61. .butright_img {
  62. position: absolute;
  63. width: 80px;
  64. height: 80px;
  65. margin: 5px;
  66. top: 0px;
  67. left: 0px;
  68. }
  69.  
  70. .textbottom {
  71. position: absolute;
  72. width: 50px;
  73. letter-spacing: 5px;
  74. color: #FFFFFF;
  75. top: 15px;
  76. left: -45px;
  77. }
  78.  
  79. .butright {
  80. position: fixed;
  81. bottom: 0px;
  82. right: %;
  83. z-index: ;
  84. color: #ffffff;
  85. }
  86.  
  87. .image {
  88. display: block;
  89. max-width: 750px;
  90. min-width: 32px;
  91. width: %;
  92. position: absolute;
  93. top: 0px;
  94. left: 0px;
  95. background: #FFFFFF;
  96. z-index: ;
  97. }
  98. </style>
  99. </head>
  100.  
  101. <body>
  102. <div id="container">
  103. <div class="container">
  104. <div class="imge">
  105. <img style="width: 100% ; position: absolute;" src="codeimg/code.jpg" />
  106. <div class="left state"></div>
  107. <div style=" position: absolute;right: 38%; margin-top: 110%;">
  108. <div class="bottom">
  109. <div class="textbottom">扫码立即注册</div>
  110. <div class="codebotom">
  111. <div id="qrcode" class="butright_img"></div>
  112. </div>
  113. </div>
  114. </div>
  115. </div>
  116. </div>
  117. <div class="butright">长按保存图片</div>
  118. </div>
  119. <div class="bot" style="position: fixed; z-index: 9999999999999999; background: #4BA59B;"></div>
  120.  
  121. </body>
  122. <!--二维码-->
  123. <script src="js/jquery.qrcode.logo.min.js" type="text/javascript" charset="utf-8"></script>
  124. <script src="js/config.js"></script>
  125. <script type="text/javascript">
  126. $(function() {
  127. var openid_list = eval(decodeURIComponent(localStorage.getItem("openid")))
  128. var openid = openid_list[]
  129. var access_token = openid_list[]
  130.  
  131. window.history.pushState(null, null, "#");
  132. window.addEventListener('popstate', function(e) {
  133. window.location.href = 'my.html'
  134. }, false);
  135.  
  136. //创建二维码
  137. function createQRCode(id, url, width, height, src) {
  138. $('#' + id).empty();
  139. jQuery('#' + id).qrcode({
  140. render: 'canvas',
  141. text: url,
  142. width: width, //二维码的宽度
  143. height: height, //二维码的高度
  144. imgWidth: width / , //图片宽
  145. imgHeight: height / , //图片高
  146. src: src //图片中央的二维码
  147. });
  148. }
  149. var url = 'https://api.gzkny.com/h5/aa.html?openid=' + openid;
  150. createQRCode("qrcode", url, , , "image/follow.jpg");
  151.  
  152. // ios系统dom-to-image方法
  153. function downloadForJS() {
  154. domtoimage.toSvg(document.getElementById('container'))
  155. .then(function(dataUrl) {
  156. /* do something */
  157. var img = new Image();
  158. img.src = dataUrl;
  159. $('.container').hide()
  160. // console.log(dataUrl)
  161. // document.body.appendChild(img);
  162. $('.bot').html(img)
  163. });
  164. }
  165.  
  166. // 禁止屏幕滑动
  167. function bodyScroll(event) {
  168. event.preventDefault();
  169. }
  170. document.body.addEventListener('touchmove', bodyScroll, false);
  171. $('body').css({
  172. 'position': 'fixed',
  173. "width": "100%"
  174. });
  175.  
  176. // 获取数据
  177. $.ajax({
  178. method: 'GET',
  179. url: window.BASE_URL + 'api/v1/member/get',
  180. contentType: 'application/x-www-form-urlencoded',
  181. async: true,
  182. dataType: "json",
  183. data: {
  184. access_token: access_token,
  185. },
  186. success: function(data) {
  187. console.log(data)
  188. if(data.error == 'success') {
  189. $('.state').html(data.data.username)
  190. downloadForJS()
  191. }
  192. }
  193. });
  194.  
  195. })
  196. </script>
  197.  
  198. </html>

html2canvas以及domtoimage的使用踩坑总结的更多相关文章

  1. html2canvas以及domtoimage的使用踩坑总结 动态获取的二维码失效如何生成海报

    //判断手机为安卓还是ios 安卓html2canvas方法 ios系统dom-to-image方法 $(".code").click(function() { var u = n ...

  2. html2canvas+Canvas2Image分享海报功能踩坑

    首先需要 import html2canvas from 'html2canvas'; import {Canvas2Image} from '../../assets/js/plug/canvas2 ...

  3. html2canvas截屏在H5微信移动端踩坑,ios和安卓均可显示

    1.最近在做移动端开发,框架是vue,一产品需求是,后台返回数据,通过qrcode.js(代码比较简单,百度上已经很多了)生成二维码,然后通过html2canvas,将html元素转化为canvas, ...

  4. html2canvas的踩坑之路

    html2canvas的踩坑之路 前言 早有耳闻这个html2canvas比较坑,但无奈于产品需求的压迫,必须实现html转图片的功能,自此走上了填坑之路,好在最后的效果还算令人满意,这才没有误了产品 ...

  5. html2canvas在Vue项目踩坑-生成图片偏移不完整

    背景 最近做一个Vue项目需求是用户长按保存图片,页面的数据是根据不同id动态生成的,页面渲染完生成内容图片让用户长按保存的时候,把整个页面都保存起来. 在项目遇到的坑是图片能生成,可是生成的图片总是 ...

  6. web前端生成图片之探索踩坑

    前段时间,产品和运营整了个非常变态的需求,要求将一个活动页面输出为图片,然后用户进行分享 开始以为是用户自己手动截图分享,没想到后来不是,细思极恐,感叹需求之变态. 从网上找了N个方案,最后确定使用  ...

  7. Spark踩坑记——Spark Streaming+Kafka

    [TOC] 前言 在WeTest舆情项目中,需要对每天千万级的游戏评论信息进行词频统计,在生产者一端,我们将数据按照每天的拉取时间存入了Kafka当中,而在消费者一端,我们利用了spark strea ...

  8. Spark踩坑记——数据库(Hbase+Mysql)

    [TOC] 前言 在使用Spark Streaming的过程中对于计算产生结果的进行持久化时,我们往往需要操作数据库,去统计或者改变一些值.最近一个实时消费者处理任务,在使用spark streami ...

  9. 【踩坑速记】二次依赖?android studio编译运行各种踩坑解决方案,杜绝弯路,总有你想要的~

    这篇博客,只是把自己在开发中经常遇到的打包编译问题以及解决方案给大家稍微分享一下,不求吸睛,但求有用. 1.大家都知道我们常常会遇到dex超出方法数的问题,所以很多人都会采用android.suppo ...

随机推荐

  1. Lightning Web Components 组合(五)

    使用组合我们可以用来设计复杂的组件. 组合一些比较小的组件,可以增加组件的重新性以及可维护性. 通过以下一个简单的demo,将会展示关于owner 以及container 的概念,在实际的项目中 ex ...

  2. 在触发器中使用{ITEM.LASTVALUE}时在首页问题栏信息显示不全

    在触发器中使用了系统宏变量,当条件满足时,如果这个宏代表的内容超过了20个字符,那么在首页信息就显示不全,会有一堆省略号 感谢https://blog.csdn.net/yu415907917/art ...

  3. (浙江金华)Day 1 组合数计数

    目录 Day 1 组合计数 1.组合数 (1).C(n,m) 读作n选m,二项式系数 : (2).n个东西里选m个的方案数 不关心选的顺序: (3).二项式系数--->多项式系数: 2.组合数计 ...

  4. 洛谷 P2085 最小函数值

    目录 题目 思路 \(Code\) 题目 戳 思路 首先这些函数全部单带递增,因为\(a\),\(b\),\(c\)都是正整数. 我们将全部的函数的\(x\)为\(1\)时的函数值放入优先度列(小根堆 ...

  5. 洛谷P4408 逃学的小孩

    题目 求树的直径,因为任意两个居住点之间有且只有一条通路,所以这是一棵树. 根据题意父母先从C去A,再去B,或者反过来. 我们一定是要让A到B最大,也要让C到A和B的最小值最大. AB最大一定就是直径 ...

  6. Invalid bound statement (not found) 错误原因

    对我来说,错误的原因是因为没有配置:mybatis.mapperLocations=classpath:mybatis/mapper/*Mapper.xmlmybatis.config-locatio ...

  7. go -- go 程序 启动docker容器

    package main import ( "io" "log" "os" "time" "github.co ...

  8. python 播放MP3和MP4

    import pygame import time def play_music(): filepath = r"900A.mp3"; pygame.mixer.init() # ...

  9. Delphi内存专题

    第一课: Windows 是多任务的操作系统, 一个任务就是一个应用(应用程序).一个应用占一个进程; 在一个进程里面, 又可以运行多个线程(所以就有了很多"多线程编程"的话题). ...

  10. 011 @Retryable的使用

    一:概述 在调用第三方接口或者使用mq时,会出现网络抖动,连接超时等网络异常,所以需要重试. 为了使处理更加健壮并且不太容易出现故障,后续的尝试操作,有时候会帮助失败的操作最后执行成功. 例如,由于网 ...