小工具知识网

当前位置: 首页 > 行业知识 > uniapp使用wxml-to-canvas开发小程序保存canvas图片

行业知识

uniapp使用wxml-to-canvas开发小程序保存canvas图片

2026-10-26 02:35:43 来源:互联网转载

微信小程序官方解决方案:wxml-to-canvas

使用wxml-to-canvas要知道一些前提条件
1、只能画view,text,image2、每个元素必须要设置宽高3、默认是flex布局,可以通过flexDirection: "column"来改变排列方式4、文字 必须放在text中,放在view中无法显示,且text不支持字体加粗5、如果你要设置背景颜色,请使用backgroundColor,而非background,border同理~6、多个absolute元素时,因为没有z-index,template元素自上而下渲染,对应z-index依次增高7、导出图片过大,可以通过canvasToTempFilePath({fileType, quality})配置里面的quality字段来减小8、image只支持临时地址和网络地址,不支持base64和本地图片,可以通过writeFile 把base64转成临时地址如下:const fs = wx.getFileSystemManager();let qrcodeBase64 = QRresult.data;let qrcodeLink = `${wx.env.USER_DATA_PATH}/qrcodeLink.gif`;fs.writeFile({    filePath: qrcodeLink,    data: qrcodeBase64,    encoding: 'base64',    success: res => {        console.log(res)        shopJson.qrcode = qrcodeLink;        this.renderToCanvas();    },    fail(res) {        console.error(res)    }})9、Canvas 初始化问题:为了正确绘制图像,需要确保在调用 canvas.draw() 之前完成所有绘制操作。10、不支持实时更新:一旦 Canvas 绘制完成,它将成为静态图像,无法实时更新。如果需要实时更新数据可视化图表,可以考虑使用其他库或组件。11、长按保存图片问题:wxml-to-canvas 组件默认无法通过长按保存图片功能保存 Canvas 图像。你可能需要自行实现该功能,并适配不同平台的实现方式。12、对低版本小程序的兼容性问题:某些较旧的微信小程序版本可能无法完全支持 wxml-to-canvas 组件。在开发之前,请确保目标用户群体的微信小程序版本。13、性能问题:复杂的数据可视化图表可能会影响性能,尤其是在绘制大量数据时。尽量优化绘制逻辑,以避免出现卡顿或延迟。14、与其他组件的兼容性问题:wxml-to-canvas 组件可能与其他小程序组件存在一些兼容性问题,导致样式错乱或布局问题。建议在使用时进行充分的测试和调试。15、跨平台问题:wxml-to-canvas 组件目前主要针对微信小程序,可能无法直接适用于其他小程序平台或移动端框架。如果需要在其他平台上实现类似的功能,可能需要另行寻找适合的解决方案。16、Canvas 绘图能力限制:由于 Canvas 的绘图能力有限,某些高级的数据可视化需求可能无法直接通过 wxml-to-canvas 组件实现。在确定方案之前,建议先了解 Canvas 绘图的限制和特性。17、样式定制问题:某些样式属性或效果可能难以通过 wxml-to-canvas 组件实现,例如阴影、渐变色等。需要根据具体需求考虑是否能够满足所需的样式效果。18、开发者工具与真机表现差异:在进行调试和预览时,开发者工具上的表现可能与真机上存在一些差异。建议进行真机测试,以确保数据可视化图表在不同设备上正常显示。等等...其他未知问题...

一、安装

npm install --save wxml-to-canvas

二、在程序根目录下新建 wxcomponents 文件夹,将node_modules下的 widget-ui 和 wxml-to-canvas 两个文件夹复制进去。

注意:这里有的安装后生成的node_modules还不一样,可直接复制dist里面的即可(如下图)

 三、将/wxcomponents/wxml-to-canvas/index.js中的

module.exports = require("widget-ui");//改为module.exports = require("../widget-ui/index.js")

 四、配置pages.json (这样uni-app才会打包wxcomponents)

  • 1. 在需要用到的页面配置
    "pages": [    {        "path": "pages/xxx",        "style": {            "usingComponents": {              "wxml-to-canvas": "/wxcomponents/wxml-to-canvas/index"            }        }    },...]
    • 2. 或者在globalStyle里面全局配置
      "globalStyle": {"navigationBarTextStyle": "black","navigationBarTitleText": "uni-app","navigationBarBackgroundColor": "#F8F8F8","backgroundColor": "#F8F8F8","usingComponents": {"wxml-to-canvas": "/wxcomponents/wxml-to-canvas/index"}},

      五、重点来了,如何使用?

      •  页面配置
                                                    {{ msg }}                    保存图片            import { wxml, style } from './DomData';export default {  data() {    return {      show: false, // 是否显示canvas      canvasWidth: 320, // 默认canvas宽高      canvasHeight: 480,      screenWidth: null, // 设备宽度      screenHeight: null, // 设备高度      // name: '',      // pic: '',      // chapter1: '',      // chapter2: '',      widget: null,      msg: '加载中,请稍等...', // 提示语      listData:[        {          type:'1',          title:'标题一',          auther: '张三  2024-01-10',          imgsrc:'https://pic1.zhimg.com/80/v2-58fe538a59f870407b1435bfd45893ed_720w.jpeg',          text:'本报讯(记者 杜晨薇)上海正在建设东方枢纽项目,浦东国际机场与沪通铁路将实现连通,枢纽周边临空产业、重点项目布局正在规划设计中。为落实上海市政府与中国东方航空集团有限公司(以下简称“中国东航”)合作协议要求,充分利用东方枢纽建设发展机遇期进一步深化合作发展,昨天下午,浦东新区政府与中国东航签署深化合作战略协议。'        },        {          type: '2',          title: '标题二',          auther: '张三  2024-01-10',          imgsrc: 'https://pic1.zhimg.com/80/v2-58fe538a59f870407b1435bfd45893ed_720w.jpeg',          text: '本报讯(记者 杜晨薇)上海正在建设东方枢纽项目,浦东国际机场与沪通铁路将实现连通,枢纽周边临空产业、重点项目布局正在规划设计中。为落实上海市政府与中国东方航空集团有限公司(以下简称“中国东航”)合作协议要求,充分利用东方枢纽建设发展机遇期进一步深化合作发展,昨天下午,浦东新区政府与中国东航签署深化合作战略协议。'        },        {          type: '3',          title: '标题三',          auther: '张三  2024-01-10',          imgsrc: 'https://pic1.zhimg.com/80/v2-58fe538a59f870407b1435bfd45893ed_720w.jpeg',          text: '本报讯(记者 杜晨薇)上海正在建设东方枢纽项目,浦东国际机场与沪通铁路将实现连通,枢纽周边临空产业、重点项目布局正在规划设计中。为落实上海市政府与中国东方航空集团有限公司(以下简称“中国东航”)合作协议要求,充分利用东方枢纽建设发展机遇期进一步深化合作发展,昨天下午,浦东新区政府与中国东航签署深化合作战略协议。'        },        {          type: '4',          title: '标题四',          auther: '张三  2024-01-10',          imgsrc: 'https://pic1.zhimg.com/80/v2-58fe538a59f870407b1435bfd45893ed_720w.jpeg',          text: '本报讯(记者 杜晨薇)上海正在建设东方枢纽项目,浦东国际机场与沪通铁路将实现连通,枢纽周边临空产业、重点项目布局正在规划设计中。为落实上海市政府与中国东方航空集团有限公司(以下简称“中国东航”)合作协议要求,充分利用东方枢纽建设发展机遇期进一步深化合作发展,昨天下午,浦东新区政府与中国东航签署深化合作战略协议。'        },        {          type: '5',          title: '标题五',          auther: '张三  2024-01-10',          imgsrc: 'https://pic1.zhimg.com/80/v2-58fe538a59f870407b1435bfd45893ed_720w.jpeg',          text: '本报讯(记者 杜晨薇)上海正在建设东方枢纽项目,浦东国际机场与沪通铁路将实现连通,枢纽周边临空产业、重点项目布局正在规划设计中。为落实上海市政府与中国东方航空集团有限公司(以下简称“中国东航”)合作协议要求,充分利用东方枢纽建设发展机遇期进一步深化合作发展,昨天下午,浦东新区政府与中国东航签署深化合作战略协议。'        },      ]    }  },  methods: {    // wxml 转 canvas    renderToCanvas() {      console.log('canvasStyle.widget', this.widget)      const _wxml = wxml(this.listData);      console.log('this.widget', _wxml)      const _style = style(this.screenWidth, this.canvasWidth, this.canvasHeight) //this.canvasHeight      const p1 = this.widget.renderToCanvas({ wxml: _wxml, style: _style })      console.log('renderToCanvas', p1)      p1.then((res) => {        console.log('海报生成成功', res);        wx.hideLoading()      }).catch((err) => {        console.log('生成失败', err)      })    },    // 保存到朋友圈    extraImage() {      if (!this.show) {        wx.showToast({ title: '海报生成失败,无法分享到朋友圈', icon: 'none' })        return      }      wx.showLoading({ title: '海报生成中...' })      const p2 = this.widget.canvasToTempFilePath({ fileType:'jpg', quality :0.5})      let that = this;      p2.then(result => {        let path = result.tempFilePath        wx.getSetting({          success: res => {            wx.hideLoading()            // 非初始化且未授权的情况,需要再次弹窗提示授权            if (res.authSetting['scope.writePhotosAlbum'] != undefined && res.authSetting['scope.writePhotosAlbum'] != true) {              wx.showModal({                title: '是否授权相册权限',                content: '需要获取相册权限,请确认授权,否则无法使用相关功能',                success: res => {                  if (res.confirm) {                    wx.openSetting({                      success: dataAu => {                        if (dataAu.authSetting["scope.writePhotosAlbum"] == true) {                          wx.showToast({                            title: '授权成功',                            icon: 'none',                            duration: 1000                          });                          that.saveIMg(path);                        } else {                          wx.showToast({                            title: '授权失败',                            icon: 'success',                            duration: 1000                          });                        }                      }                    });                  }                }              });            } else {              // 初始化且未授权,系统默认会弹窗提示授权              // 非初始化且已授权,也会进入这里              that.saveIMg(path);            }          }        });      })    },    // 保存到相册    async saveIMg(tempFilePath) {      wx.saveImageToPhotosAlbum({        filePath: tempFilePath,        success: async (res) => {          wx.showModal({            content: '图片已保存,分享给好友吧!',            showCancel: false,            confirmText: '好的',            confirmColor: '#333',            success: function (res) {              wx.navigateBack({                //返回                delta: 1              });            },            fail: function (res) {              console.log('res', res);            }          });        },        fail: function (res) {          wx.showToast({            title: '您取消了授权',            icon: 'none',            duration: 2000          })        }      });    },  },  onLoad(options) {    console.log('options', options);    // 获取设备信息    wx.getSystemInfo({      success: (res) => {        console.log('屏幕',res)        this.screenWidth = res.screenWidth;        this.canvasWidth = this.screenWidth;        this.canvasHeight = this.screenWidth * 8.5;        console.log('海报高度:', this.canvasHeight)        this.show = true        // 数字容器宽度 动态设置         setTimeout(() => {          wx.showLoading({ title: '海报加载中...' })          this.widget = this.selectComponent('.widget')          this.renderToCanvas()        }, 1000)      }    });  },}.share-page {  background: #cc0202;  position: relative;  overflow: hidden;  // padding: 10rpx;//   min-height: 100vh;  .msg-box {    display: flex;    align-items: center;    text-align: center;    justify-content: center;  }  .share-page-box {    margin: 0 auto;    position: relative;    overflow: hidden;  box-shadow: 0rpx 6rpx 20rpx 6rpx rgba(0, 0, 0, 0.2);  }  .share-page-btn {    margin: 0 10rpx 0 10rpx;    img {      width: 100%;      height: 100%;    }  }}
        • DomData.js

          /** * * @param {*} listData  canvas数据 */export const wxml = (listData) => `  ${listData.map(item=>{    return `                          `+ item.title + `        `+ item.auther + `                                      `+ item.text+`                  `  }).join('')}`/** * * * @param {*} screenWidth 屏幕宽度 * @param {*} canvasWidth  画布宽度 * @param {*} canvasHeight  画布高度 * @param {*} numberWidth  数字宽度,动态设置 * @return {*}  */ export const style = (screenWidth, canvasWidth, canvasHeight) => {  return {    "container": {      width: canvasWidth,      minHeight: canvasHeight,      position:'relative',      backgroundColor: '#ffffff',      justifyContent: 'center',      alignItems:'center',      overflow: 'hidden'    },    "bottomcss":{      marginTop: 0,    },    "contentWrap":{      position: 'relative',      width: canvasWidth * 0.99,      marginBottom: 20,      marginTop: 5,      marginLeft: 1,      borderRadius: 20,      overflow:'hidden',      backgroundColor: '#333333',    },    "imgbc":{      justifyContent: 'center',      alignItems: 'center',      width: canvasWidth * 0.97,      height: canvasWidth,      marginBottom: 4,      marginLeft: 4,      marginTop: 10,      borderRadius: 20,      overflow: 'hidden',    },    "tapContent1":{      position:'absolute',      top: 0,      left: 0,    },    "tapname":{      fontSize: 18,      color: '#fff',      marginLeft: 15,      marginTop: 50,      overflow: 'hidden',      width: canvasWidth * 0.92,      height: 400,      textAlign: 'left',    },    "name":{      fontSize: 20,      color: '#fff',      marginLeft: canvasWidth * 0.08,      width: canvasWidth * 0.84,      height: 30,textAlign: 'center',    },    "subtitle":{      fontSize: 14,      color: '#9E9C9C',      marginLeft: canvasWidth * 0.08,      width: canvasWidth * 0.84,      height: 20,      textAlign: 'center',    },    "content": {fontSize: 14,color: '#333',      width: canvasWidth * 0.84,      height: screenWidth * 0.15,marginLeft: canvasWidth * 0.08,    },    "pic1": {      width: canvasWidth * 0.3,      height: screenWidth * 0.3,      marginTop: canvasWidth * 0.1,      marginLeft: canvasWidth * 0.35,marginBottom: canvasWidth * 0.05,borderRadius: screenWidth * 0.14,overflow: 'hidden',    },    "pic2": {      width: canvasWidth ,      height: canvasWidth ,      marginTop:10,    },    "bottom":{      width: canvasWidth,      height: screenWidth * 0.2,      flexDirection: 'row',      justifyContent: 'self-start',      alignItems: 'center',backgroundColor: '#fafafa',      position: 'absolute',      bottom: 0,      left: 0,    },"qr": {  width: canvasWidth * 0.14,  height: screenWidth * 0.14,  marginLeft: canvasWidth * 0.04,marginRight: canvasWidth * 0.04,},    "msg": {      fontSize: 14,      color: '#a1a1a1',      width: canvasWidth * 0.74,height: 14,textAlign: 'left'    },  }}

           


          六、生成的效果图

           


          ...... 全 剧 终 ......

上一篇:怎么让网页连接php服务器?

下一篇:揭秘PHP自动采集技巧,轻松实现内容高效抓取与整合