フロントエンドH5でスクリーンショットを共有する方法

目次

序文

この記事では、主にキャンバスを使ってスクリーンショットを共有する方法を紹介します。
最初はキャンバスペインティングで写真を共有するのは難しいことではないと思いましたが、実際には開発中にまだ多くの落とし穴があります。
例:
①写真の背景が透明
②写真は共有のみテキストに画像がありません
。③画像のクロスドメインの問題
例を見てみましょう
。共有画像、共有コンテンツの説明、タイトル、QRコードはリクエストインターフェースを介して動的に生成されます

ここに写真の説明を挿入

実現:まず、体の部分

私が使用するフレームワークはreactです。絵画の共有は、ネイティブキャンバスとjsによって実現されます。したがって、vue、applets、およびネイティブH5について心配する必要はありません。

1.キャンバスを作成し、
以下にいくつか表示します内联代码片

//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>

実現:2、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},()=>{
    
     
    })
  }

実現:3つ、Canvasはimgを置き換えます


//最后必须将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>

まとめと最適化

難点は次の
とおりです。①キャンバスをbase64形式の画像に変換すると、クロスドメイン画像の問題が発生します
②非同期の問題(画像が読み込まれていない、ペイントが完了している)
③背景の透明度の問題など。

最適化:
①シャープネス:キャンバスを2〜4倍描画し、画像に変換してから50%
〜25 %に圧縮できます②画像共有の読み込み速度:ミニプログラムQRコードサンコード、背景画像、その他のページ読み込み段階を最初に行うことができますリクエスト、共有ボタンをクリックして直接描画し、リクエスト時間が長くなることによる描画生成の遅延の問題を軽減し、ロードされていない2次元コードと背景画像を回避して描画を開始すると、背景画像なしで共有画像が2次元で描画されますコードの問題。

困っている友達は研究を参照することができます。欠点がある場合は、批判や訂正を歓迎します。

おすすめ

転載: blog.csdn.net/qq_45108245/article/details/112240186