经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » HTML/CSS » HTML5 » 查看文章
前端Html5如何实现分享截图的示例代码
来源:jb51  时间:2021/3/29 8:52:33  对本文有异议

前言

这篇文章主要是介绍如何使用canvas实现分享截图,
刚开始以为通过canvas绘画分享图片并不难,但实际上在开发的时候还是遇到非常多的坑
例如:
①图片背景为透明
②分享图只有文字没有图片
③图片跨域问题
下面看例子:
分享图片、分享内容描述、标题、二维码都是通过请求接口动态生成

实现:一、body部分

框架我使用的是react。绘画分享采用原生canvas、js实现。所以不用担心vue、小程序、原生H5也是能够适应。

一、构建canvas

下面展示一些 内联代码片。

  1. //ref是react获取canvas元素的方法。也可以使用id,再通过getElementById() 方法获取canvas
  2. //宽高需要转化为而二-四倍图来提高清晰度、否则会导致分享截图模糊,清晰度不足
  3. <canvas ref='canvas' width={1200} height={1600} className={styles.canvasImg}/>
  1. //点击分享按钮触发this.shareComponent(this.getUrlImg)方法
  2. //非react框架,忽视其余代码。直接触发分享函数
  3. <div className={styles.luckDraw_viewPrizeBtn} onClick={()=>{
  4. this.setState({
  5. shareModal:true
  6. },()=>{
  7. this.shareComponent(this.getUrlImg)
  8. })}
  9. }>分享活动</div>

实现:二、JS部分:

shareComponent函数

  1. //函数接受一个回调函数,用于绘画完成后,再将canvas转化为png图片格式。
  2. //canvas移动端无法长按保存,必须传为img才能保存。
  3. shareComponent = (callback)=>{
  4. let suncode = this.state.suncode //微信小程序太阳码
  5. let activityName = this.state.activityName //活动标题
  6. let backgroundImg = this.state.backgroundImg //背景图
  7. let postShareDesc= this.state.postShareDesc //分享描述字段
  8. let img = new Image()
  9. img.crossOrigin="anonymous"; //关键,处理图片跨域问题!!
  10. let _t = this
  11. //限制活动标题,最多10个字,超过...省略
  12. if(activityName.length>10){
  13. activityName=activityName.slice(0,10)+'...'
  14. }
  15. //由于canvas文字不能自动换行,所以我们这里需要做一个文字换行处理,以及字数的限制,防止超出canvas范围
  16. let arrDescribe = []
  17. let maxLeng = postShareDesc.length/20 //分享描述每行20字,最多8行
  18. if(maxLeng=>8){
  19. maxLeng = 8 //最多8行
  20. }
  21. //postShareDesc为分享描述字段
  22. for(let i = 0;i<maxLeng;i++){
  23. //将分享描述字段分为若干个20字的行存入arrDescribe数组,且最多8行
  24. let str = postShareDesc.slice(i*20,i*20+20)
  25. arrDescribe.push(str)
  26. }
  27. //图片加载完后,将其显示在canvas中,图片必须使用onload方式,否则会导致图片未加载完成就完成绘画
  28. //img为整张分享图
  29. img.onload = function (){
  30. let canvas = _t.refs.canvas //获取canvas元素
  31. let ctx = canvas.getContext('2d')
  32. //设置背景色,否则背景色会透明
  33. ctx.fillStyle='#fff';
  34. ctx.fillRect(0,0,1196,1596);
  35. ctx.drawImage(img, 0, 0,1200,600);
  36. //分享字段描述
  37. ctx.font="52px Arial";
  38. ctx.fillStyle='#000';
  39. //手动换行,80为X坐标,700+index*100为动态计算Y坐标
  40. arrDescribe.forEach((item,index)=>{
  41. ctx.fillText(item,80,700+index*100);
  42. })
  43. //分享标题
  44. ctx.font="64px Arial";
  45. ctx.fillStyle='#000';
  46. ctx.fillText(activityName,520,1320);
  47. //分享提示
  48. ctx.font="48px Arial";
  49. ctx.fillStyle='#999';
  50. ctx.fillText('长按小程序码查看详情',520,1420);
  51. //分享提示
  52. ctx.font="48px Arial";
  53. ctx.fillStyle='#999';
  54. ctx.fillText('分享自[XXXX]',520,1500);
  55. //分割线
  56. ctx.moveTo(1120,1160);
  57. ctx.lineTo(80,1180);
  58. ctx.strokeStyle="#E8E8E8"
  59. ctx.stroke();
  60. //img1为小程序太阳码
  61. let img1 = new Image()
  62. img1.crossOrigin="anonymous"; //关键,处理太阳码转化为base64格式图片时的跨域问题
  63. img1.onload = function(){
  64. ctx.drawImage(img1, 80, 1200,340,340)
  65. callback(canvas)
  66.  
  67. }
  68. 太阳码赋值给img1
  69. img1.src = suncode
  70. //边框
  71. ctx.strokeStyle="#f5f5f5";
  72. ctx.rect(0,0,1200,1600);
  73. ctx.stroke();
  74.  
  75. }
  76. //timeStamp 事件属性可返回一个时间戳。指示发生事件的日期和时间(从 epoch 开始的毫秒数)。
  77. //URL时间戳的用法:作用:为了防止浏览器缓存。
  78. //URL后面添加随机数或时间戳通常用于防止浏览器(客户端)缓存页面。 浏览器缓存是基于URL进行缓存的,
  79. //如果页面允许缓存,则在缓存时效前再次访问相同的URL,浏览器就不会再次发送请求到服务器端,而是直接从缓存中获取指定资源。
  80. //而当URL 的末尾追加了随机数或时间戳,就会保证每次都会实际生成新请求且 Web 服务器不会尝试缓存来自服务器的响应。
  81. const a = `${backgroundImg}?timeStamp=` + (new Date());
  82. img.src = a
  83.  
  84. }
  85. //绘画完成后,必须转化为img,否则移动端将会无法长按保存
  86. //必须等绘画完成后,才能够回调。如果直接使用canvas.toDataURL('image/png')转化,会导致出现分享图只有写死的文字,没有请求的图片和文字。会存在异步问题
  87. getUrlImg=(canvas)=>{
  88. let dataImg = new Image()
  89. try {
  90. dataImg.src = canvas.toDataURL('image/png')
  91. } catch (e) {
  92. console.log(e);
  93. }
  94. let urlImg = dataImg.src //urlImg为img路径
  95. this.setState({urlImg},()=>{
  96. })
  97. }

实现:三、canvas更换imgs

  1. //最后必须将canvas隐藏,再替换为imgs,这样移动端才能长按保存
  2. //css中.canvasImg添加display:none隐藏画布
  3. //再使用canvas转化的img,并且将img的宽高设置为25%
  4. //因为为了提高清晰度,我是采用四倍图再压缩的方式来提高清晰度,所以img需要缩回25%
  5. <canvas ref='canvas' width={1200} height={1600} className={styles.canvasImg}/>//display:none
  6. //crossOrigin="Anonymous" 处理图片跨域问题
  7. <img src={this.state.urlImg} crossOrigin="Anonymous"/>//width:25%。height:25%
  8. div className={styles.shareTips}>长按保存,可分享至朋友圈</div>

总结与优化

难点在于:
①将canvas转化为base64格式图片,会导致图片跨域问题
②异步问题(图片还未加载,绘画就已经完成)
③背景透明的问题等等

优化:
①清晰度:可以将canvas画成2-4倍图,转化为图片再压缩回50%-25%
②分享图加载速度:小程序二维码太阳码,背景图等页面加载阶段可以先请求,点击分享按钮可以直接绘画,减少请求时间长导致生成绘画慢问题,同时也可以避免二维码、背景图未加载完成,绘画就已经开始,导致画出来的分享图没有背景图、二维码的问题。

到此这篇关于前端Html5如何实现分享截图的示例代码的文章就介绍到这了,更多相关Html5分享截图内容请搜索w3xue以前的文章或继续浏览下面的相关文章,希望大家以后多多支持w3xue!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号