uniapp使用wxml-to-canvas开发小程序保存canvas图片
微信小程序官方解决方案:wxml-to-canvas
使用wxml-to-canvas要知道一些前提条件
1、只能画view,text,image 2、每个元素必须要设置宽高 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' }, } }
六、生成的效果图
...... 全 剧 终 ......
-
-
-
免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。