当前位置: 首页 > article >正文

uniapp小程序分享使用canvas自定义绘制 vue3

使用混入结合canvas做小程序的分享
在混入里面定义一个全局共享的分享样式,在遇到特殊页面需要单独处理

utils/share.js

import { ref } from 'vue';
export default {
  onShow() {
    // 创建时设置统一页面的默认值
    uni.$mpShare = {
      title: '分享的标题',
      path: '/pages/home/home',
      imageUrl: 'https:xxx',
      success: function (res) {
        // 转发成功之后的回调
        console.log('转发成功之后的回调', res);
        if (res.errMsg == 'shareAppMessage:ok') {}
      },
      fail: function () {
        // 转发失败之后的回调
        console.log('转发失败之后的回调', res);
        if (res.errMsg == 'shareAppMessage:fail cancel') {
          // 用户取消转发
        } else if (res.errMsg == 'shareAppMessage:fail') {
          // 转发失败,其中 detail message 为详细失败信息
        }
      },
    };
  },
  //发送给朋友
  onShareAppMessage(res) {
    console.log(' uni.$mpShare-----------', uni.$mpShare);
    return uni.$mpShare;
  },
  //分享到朋友圈
  onShareTimeline(res) {
    return uni.$mpShare;
  },
};

main.js混入

import share from '/utils/share.js';
export function createApp() {
  const app = createSSRApp(App);
  app.use(Pinia.createPinia());
  app.mixin(share); // 这里
  app.use(uviewPlus);
  return {
    app,
    Pinia,
  };
}

Canvas绘制海报
commonShare.js

/**
 * canvas
 * context
 * currentObj 绘制需要用到的对象
 * bgImg 背景图
 * dpr 设备分辨率
 * type 类型
 */

export async function createPoster(canvas, context, currentObj, bgImg, dpr, type) {
  const bgImage = await renderImg(canvas, bgImg);

  //绘制矩形
  context.drawImage(bgImage, 0, 0, canvas.width / dpr, canvas.height / dpr);
  context.fillStyle = '#FFF';
  context.strokeStyle = '#303030';
  context.lineWidth = 2;
  context.strokeRect(16, 100, 343, 180);
  context.fillRect(16, 100, 343, 180);
    switch (type) {
    //周边商品
    case 'periphery':
      //绘制商品图片
      const productPath = showPicture(currentObj.goodsPictures[0].picture);
      const productImg = await renderImg(canvas, productPath);
      context.drawImage(productImg, 28, 112, 150, 157);
      //绘制商品名称
      context.font = 'normal normal bold 19px SourceHanSansCN-Bold';
      context.fillStyle = '#0D1932';
      context.fillText(currentObj.goodsName, 189, 136);

      //绘制¥
      context.font = 'normal normal bold 25px SourceHanSansCN-Bold';
      context.fillStyle = '#FE2A12';
      context.fillText(`${currentObj.giftPrice}.${currentObj.giftPricePrefix}`, 189, 256);
    break;
}
  let path = await generatePath(context);
  console.log('分享图片', path);
  return path;
}

//图片显示
function showPicture(srcPath) {
  if (srcPath.includes('http')) {
    return srcPath;
  } else {
    return 'https://xxxxxx' + srcPath; // 注意路径
  }
}

//创建图片对象
function renderImg(canvas, url) {
  // url传临时路径
  return new Promise((resolve) => {
    const img = canvas.createImage();
    img.src = `${url}?timestamp=${new Date().getTime()}`;
    img.onload = () => {
      resolve(img);
    };
  });
}

function base64src(base64data, fun) {
  const base64 = base64data; //base64格式图片
  const time = new Date().getTime();
  const imgPath = uni.env.USER_DATA_PATH + '/poster' + time + 'share' + '.png';
  //如果图片字符串不含要清空的前缀,可以不执行下行代码.
  const imageData = base64.replace(/^data:image\/\w+;base64,/, '');
  const file = uni.getFileSystemManager();
  file.writeFileSync(imgPath, imageData, 'base64');
  fun(imgPath);
}

async function generatePath(context) {
  let base64IMG = context.canvas.toDataURL();
  let pathImg = '';
  await base64src(base64IMG, (res) => {
    pathImg = res;
  });
  return pathImg;
}

Canvas.createImage() 创建Image对象onload事件在安卓真机下只会触发一次,
确保每次加载的 URL 是唯一的:通过在 URL 后面添加一个时间戳或随机数来避免缓存问题。

img = `${url}?timestamp=${new Date().getTime()}`;

单独页面的处理xxxx.vue

<view id="canvas" v-show="false">
   <canvas id="myCanvas" type="2d" canvas-id="myCanvas" style="width: 375px; height: 300px"></canvas>
</view>

<script setup>
//引入分享绘制canvas
import { createPoster } from '/utils/commonShare.js';
onShow(() => {
   generatorCanvasUrl();
});

function generatorCanvasUrl() {
   uni
     .createSelectorQuery()
     .select('#myCanvas')
     .node((res) => {
       let canvas = res.node;
       let context = res.node.getContext('2d');
       uni.getSystemInfo({
         success: async function (sysRes) {
           const dpr = sysRes.devicePixelRatio;
           canvas.width = 375 * dpr;
           canvas.height = 300 * dpr;
           context.clearRect(0, 0, canvas.width, canvas.height);
           context.scale(dpr, dpr);
           let path = await createPoster(canvas, context, currentObj.value, canvasBgImg.value, dpr, canvasType.value);
           uni.$mpShare = {
             title: canvasTitle.value,
             path: '/pagesDiscover/group/group-product-dedails?from=sharePage&data=' + encodeURIComponent(JSON.stringify(currentObj.value)),
             imageUrl: path,
           };
           console.log('重绘成功');
         },
       });
     })
     .exec();
 }
</script>

注意几个问题

  1. canvas的绘制时间,需要在拿到数据之后,dom生成之前绘制完成,onShow不可以就试试onReady,否则就会绘制失败(图片找不到,数据undefined)
  2. 图片路径后面一定要加时间戳保证图片路径是唯一的,否则就会一直走缓存
  3. 如果页面想要重置分享但是不用canvas绘制,直接用下面这个
const shareData = computed(() => {
  // 分享的数据
  return {
    title: '重置',
    desc: '重置',
    path: '/xxxx/xxxx/xxxx',
    imageUrl: 'xxxxx',
  };
});
onShow(() => {
  uni.$mpShare = shareData.value; // 修改uni.$mpShare的值
});

http://www.kler.cn/a/395569.html

相关文章:

  • Android setTheme设置透明主题无效
  • 用 Python 从零开始创建神经网络(三):添加层级(Adding Layers)
  • Wireshark中的length栏位
  • vue2使用 <component> 标签动态渲染不同的表单组件
  • Android 13 实现屏幕熄屏一段时候后关闭 Wi-Fi 和清空多任务列表
  • 机器学习在医疗健康领域的应用
  • 【开源免费】基于SpringBoot+Vue.JS高校学科竞赛平台(JAVA毕业设计)
  • 【MYSQL】数据库三大范式是什么?【最简单理解】
  • 多端校园圈子论坛小程序,多个学校同时代理,校园小程序分展示后台管理源码
  • ‌MySQL 5.7和8.0版本在多个方面存在显著区别,主要包括性能优化、新特性引入以及安全性提升
  • 2:Vue.js 父子组件通信:让你的组件“说话”
  • git命令提交项目
  • 适用比亚迪汽车生产线的RFID高频读写器
  • 为什么 Vue3 封装 Table 组件丢失 expose 方法呢?
  • 鸿蒙学习-PersistentStorage持久化存储
  • 【递归回溯与搜索算法篇】算法的镜花水月:在无尽的自我倒影中,递归步步生花
  • 深入浅出:Java 中的经典排序算法详解与实现
  • 1、C语言学习专栏介绍
  • 排序算法 -归并排序
  • 机器学习的常用算法
  • SQLite3 JDBC Java工具类
  • 网站部署到IIS后,数据库登录失败
  • 一百多块可以买到什么样的开放式耳机?虹觅Olite评测推荐
  • 机器学习—诊断偏差和方差
  • 两路组相联缓存配置
  • 【Rust调用Windows API】获取正在运行的全部进程信息