最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 前端H5实现分享截图

    正文概述 掘金(蟑螂恶霸y)   2021-02-04   533

    前言

    这篇文章主要是介绍如何使用canvas实现分享截图, 刚开始以为通过canvas绘画分享图片并不难,但实际上在开发的时候还是遇到非常多的坑 例如:

    ①图片背景为透明

    ②分享图只有文字没有图片

    ③图片跨域问题

    下面看例子: 分享图片、分享内容描述、标题、二维码都是通过请求接口动态生成

    前端H5实现分享截图

    实现:一、body部分

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

    一、构建canvas 下面展示一些 内联代码片

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

    实现:二、JS部分:

    shareComponent函数

    //函数接受一个回调函数,用于绘画完成后,再将canvas转化为png图片格式。
    //canvas移动端无法长按保存,必须传为img才能保存。
    shareComponent = (callback)=>{
        let suncode = this.state.suncode //微信小程序太阳码
        let activityName = this.state.activityName //活动标题
        let backgroundImg = this.state.backgroundImg //背景图
        let postShareDesc= this.state.postShareDesc //分享描述字段
        let img = new Image()
        img.crossOrigin="anonymous"; //关键,处理图片跨域问题!!
        let _t = this
        //限制活动标题,最多10个字,超过...省略
        if(activityName.length>10){
            activityName=activityName.slice(0,10)+'...'
          }
        //由于canvas文字不能自动换行,所以我们这里需要做一个文字换行处理,以及字数的限制,防止超出canvas范围
        let arrDescribe = [] 
        let maxLeng = postShareDesc.length/20 //分享描述每行20字,最多8行
        if(maxLeng=>8){
            maxLeng = 8 //最多8行
        }
        //postShareDesc为分享描述字段
       
        for(let i = 0;i<maxLeng;i++){
        //将分享描述字段分为若干个20字的行存入arrDescribe数组,且最多8行
            let str = postShareDesc.slice(i*20,i*20+20) 
            arrDescribe.push(str)
        }
        //图片加载完后,将其显示在canvas中,图片必须使用onload方式,否则会导致图片未加载完成就完成绘画
        //img为整张分享图
        img.onload = function (){
          let canvas = _t.refs.canvas //获取canvas元素
          let ctx = canvas.getContext('2d')
            //设置背景色,否则背景色会透明
            ctx.fillStyle='#fff';
            ctx.fillRect(0,0,1196,1596);
            ctx.drawImage(img, 0, 0,1200,600);
    		//分享字段描述
            ctx.font="52px Arial";
            ctx.fillStyle='#000';
            //手动换行,80为X坐标,700+index*100为动态计算Y坐标
            arrDescribe.forEach((item,index)=>{
                ctx.fillText(item,80,700+index*100);
            })
            //分享标题
            ctx.font="64px Arial";
            ctx.fillStyle='#000';
            ctx.fillText(activityName,520,1320);
    		//分享提示
            ctx.font="48px Arial";
            ctx.fillStyle='#999';
            ctx.fillText('长按小程序码查看详情',520,1420);
    		//分享提示
            ctx.font="48px Arial";
            ctx.fillStyle='#999';
            ctx.fillText('分享自[XXXX]',520,1500);
    		//分割线
            ctx.moveTo(1120,1160);
            ctx.lineTo(80,1180);
            ctx.strokeStyle="#E8E8E8"
            ctx.stroke();
            //img1为小程序太阳码
            let img1 = new Image()
            img1.crossOrigin="anonymous"; //关键,处理太阳码转化为base64格式图片时的跨域问题
            img1.onload = function(){
            ctx.drawImage(img1,  80, 1200,340,340)
            callback(canvas)
    
          }
    	  太阳码赋值给img1
          img1.src = suncode
    	  //边框
          ctx.strokeStyle="#f5f5f5";
          ctx.rect(0,0,1200,1600);
          ctx.stroke();      
    
        }
    	//timeStamp 事件属性可返回一个时间戳。指示发生事件的日期和时间(从 epoch 开始的毫秒数)。
    	//URL时间戳的用法:作用:为了防止浏览器缓存。
    	//URL后面添加随机数或时间戳通常用于防止浏览器(客户端)缓存页面。 浏览器缓存是基于URL进行缓存的,
    	//如果页面允许缓存,则在缓存时效前再次访问相同的URL,浏览器就不会再次发送请求到服务器端,而是直接从缓存中获取指定资源。
    	//而当URL 的末尾追加了随机数或时间戳,就会保证每次都会实际生成新请求且 Web 服务器不会尝试缓存来自服务器的响应。
        const a = `${backgroundImg}?timeStamp=` + (new Date());
        img.src = a
    
      }
    //绘画完成后,必须转化为img,否则移动端将会无法长按保存
    //必须等绘画完成后,才能够回调。如果直接使用canvas.toDataURL('image/png')转化,会导致出现分享图只有写死的文字,没有请求的图片和文字。会存在异步问题
      getUrlImg=(canvas)=>{   
        let dataImg = new Image()    
        try {
          dataImg.src = canvas.toDataURL('image/png')
        } catch (e) {
          console.log(e);
        }
        let urlImg = dataImg.src //urlImg为img路径
        this.setState({urlImg},()=>{ 
        })
      }
    

    实现:三、canvas更换imgs

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

    总结与优化

    难点在于:

    ①将canvas转化为base64格式图片,会导致图片跨域问题

    ②异步问题(图片还未加载,绘画就已经完成)

    ③背景透明的问题等等

    优化:

    ①清晰度:可以将canvas画成2-4倍图,转化为图片再压缩回50%-25%

    ②分享图加载速度:小程序二维码太阳码,背景图等页面加载阶段可以先请求,点击分享按钮可以直接绘画,减少请求时间长导致生成绘画慢问题,同时也可以避免二维码、背景图未加载完成,绘画就已经开始,导致画出来的分享图没有背景图、二维码的问题。

    有需要的朋友可以参考学习下。如有不足之处,欢迎批评指正。


    起源地下载网 » 前端H5实现分享截图

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元