IT技术之家

首页 > 小程序

小程序

uni-app 微信小程序 图文生成图片 wxml-to-canvas_奋斗的小岛ssnnyy

发布时间:2023-12-10 01:07:54 小程序 136次 标签:微信小程序 uni-app 小程序
使用uni-app框架实现在微信小程序上把动态生成的文字和签名生成图片,使用微信小程序的 wxml-to-canvas技术。html2canvas不兼容小程序,目前只知道此方式...

在做的小程序要增加一个将文字与图片生成图片不可修改的功能,第一次做,在网上找了不少资料。参考了wxml-to-canvas | 微信开放文档? ,又看了一些相关事例,尝试写了一下。
?

需要准备的文件及配置项:

1、先把代码片段下载到本地

2、创建wxcomponents目录,把代码片段中的文件拷到此目录下,并将下图的目录改成真实目录。

3、修改配置文件pages.json,找到要写此功能的路径,加上

"style": {
?? ??? ??? ??? ?"app-plus": {
?? ??? ??? ??? ??? ?"titleNView": false //禁用原生导航栏
?? ??? ??? ??? ?},
?? ??? ??? ??? ?"navigationBarTitleText": "",
?? ??? ??? ??? ?"enablePullDownRefresh": false,
?? ??? ??? ??? ?"navigationStyle": "custom",
?? ??? ??? ??? ?"usingComponents":{
?? ??? ??? ??? ??? ?"wxml-to-canvas": "/wxcomponents/wxml-to-canvas/index"
?? ??? ??? ??? ?}
?? ??? ??? ?}

?

?4、开始写组件。注意this.widget = this.selectComponent('.widget');一定要放在onLoad页面生命周期中,不然不生效

?<view :style="{width: canvasWidth + 'px', height: canvasHeight + 'px' }">
?? ??? ?<wxml-to-canvas class="widget" :width="canvasWidth" :height="canvasHeight"></wxml-to-canvas>
?? ?</view>

const {
?? ??? ?wxml,
?? ??? ?style
?? ?} = require('./notification.js')
?? ?export default {
?? ??? ?data() {
?? ??? ??? ?return {
?? ??? ??? ??? ?imgSrc: '/static/img/3.png',
?? ??? ??? ??? ?//最后生成的图片信息
?? ??? ??? ??? ?imageData: null,
?? ??? ??? ??? ?canvasWidth: 320, // 默认canvas宽高
?? ??? ??? ??? ?canvasHeight: 480,
?? ??? ??? ??? ?screenWidth: null, // 设备宽度
?? ??? ??? ??? ?screenHeight: null, // 设备宽度
?? ??? ??? ??? ?userInfo: {},
?? ??? ??? ??? ?isRegister: '',
?? ??? ??? ??? ?controlContent: undefined,
?? ??? ??? ??? ?statusCode: undefined,
?? ??? ??? ??? ?//上个页面用到的图片地址
?? ??? ??? ??? ?tempFile:undefined
?? ??? ??? ?}
?? ??? ?},
?? ??? ?onLoad(option) {
?? ??? ??? ?this.userInfo = uni.getStorageSync('weixin-userInfo') ? JSON.parse(uni.getStorageSync('weixin-userInfo')) :{};
?? ??? ??? ?// 获取设备信息
?? ??? ??? ?wx.getSystemInfo({
?? ??? ??? ??? ?success: (res) => {
?? ??? ??? ??? ??? ?this.screenWidth = res.screenWidth
?? ??? ??? ??? ??? ?this.screenHeight = 800 //高度建议计算得出或写死。如使用res.screenHeight,文字过长时无法生成(安卓手机,最新鸿蒙系统高度不能超过1000)
?? ??? ??? ??? ??? ?this.canvasWidth = this.screenWidth
?? ??? ??? ??? ??? ?this.canvasHeight = this.screenHeight
?? ??? ??? ??? ??? ?setTimeout(() => {
?? ??? ??? ??? ??? ??? ?this.widget = this.selectComponent('.widget');
?? ??? ??? ??? ??? ??? ?this.controlContent = option.controlContent;
?? ??? ??? ??? ??? ??? ?this.tempFile = option.tempFile
?? ??? ??? ??? ??? ??? ?this.download();
?? ??? ??? ??? ??? ?}, 1000)
?? ??? ??? ??? ?}
?? ??? ??? ?});
?? ??? ?},
?? ??? ?methods: {
?? ??? ??? ?//生成图片
?? ??? ??? ?download() {
?? ??? ??? ??? ?// 数字容器宽度 动态设置?
?? ??? ??? ??? ?setTimeout(() => {
?? ??? ??? ??? ??? ?uni.showLoading({
?? ??? ??? ??? ??? ??? ?title: '图片生成中...'
?? ??? ??? ??? ??? ?})
?? ??? ??? ??? ??? ?this.renderToCanvas()
?? ??? ??? ??? ?}, 1000)
?? ??? ??? ?},
?? ??? ??? ?renderToCanvas() {
?? ??? ??? ??? ?const _wxml = wxml('test', this.tempFile, this.controlContent) //调用wxml
?? ??? ??? ??? ?const _style = style(this.screenWidth, this.canvasWidth, this.canvasHeight)
?? ??? ??? ??? ?setTimeout(() => {
?? ??? ??? ??? ??? ?const p1 = this.widget.renderToCanvas({
?? ??? ??? ??? ??? ??? ?wxml: _wxml,
?? ??? ??? ??? ??? ??? ?style: _style
?? ??? ??? ??? ??? ?})
?? ??? ??? ??? ??? ?p1.then((res) => {
?? ??? ??? ??? ??? ??? ?uni.hideLoading()
?? ??? ??? ??? ??? ??? ?this.saveImageToPhotosAlbum();
?? ??? ??? ??? ??? ?}).catch((err) => {
?? ??? ??? ??? ??? ??? ?console.log('生成失败')
?? ??? ??? ??? ??? ?})
?? ??? ??? ??? ?}, 100)

?? ??? ??? ?},
?? ??? ??? ?//保存图片到本地
?? ??? ??? ?saveImageToPhotosAlbum() {
?? ??? ??? ??? ?uni.showLoading({
?? ??? ??? ??? ??? ?title: '正在保存中...'
?? ??? ??? ??? ?})
?? ??? ??? ??? ?const p2 = this.widget.canvasToTempFilePath()
?? ??? ??? ??? ?let that = this
?? ??? ??? ??? ?p2.then(result => {
?? ??? ??? ??? ??? ?let path = result.tempFilePath
?? ??? ??? ??? ??? ?uni.uploadFile({
?? ??? ??? ??? ??? ??? ?url: this.$u.http.config.baseUrl + '/yd/img/upload',
?? ??? ??? ??? ??? ??? ?filePath: path,
?? ??? ??? ??? ??? ??? ?name: 'file',
?? ??? ??? ??? ??? ??? ?formData: {
?? ??? ??? ??? ??? ??? ??? ?'user': 'test'
?? ??? ??? ??? ??? ??? ?},
?? ??? ??? ??? ??? ??? ?success: (res) => {
?? ??? ??? ??? ??? ??? ??? ?let data = JSON.parse(res.data)
?? ??? ??? ??? ??? ??? ??? ?if (data.code == 200) {
?? ??? ??? ??? ??? ??? ??? ??? ?let params = {
?? ??? ??? ??? ??? ??? ??? ??? ??? ?signUrl: data.fileName,
?? ??? ??? ??? ??? ??? ??? ??? ??? ?personId: JSON.parse(uni.getStorageSync('storage_signStatus')).personId,
?? ??? ??? ??? ??? ??? ??? ??? ??? ?signUnionId: this.userInfo.openid,
?? ??? ??? ??? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ??? ??? ??? ?this.$u.api.ydSignEdit(params).then(rest => {
?? ??? ??? ??? ??? ??? ??? ??? ??? ?if (rest.code == 200) {
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?uni.saveImageToPhotosAlbum({
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?filePath: path,
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?success: ()=> {
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?uni.hideLoading()
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?uni.showToast({
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?title: '保存成功,可去手机相册查看',
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?duration: 2000,
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?icon: 'none'
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?});
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?/* uni.redirectTo({
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?url: '../communityControl/notification?tempFile='+ this.tempFile?? ?
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?});?? ? */
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?uni.navigateBack();
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?});
?? ??? ??? ??? ??? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ??? ??? ??? ?}).catch(error => {
?? ??? ??? ??? ??? ??? ??? ??? ??? ?uni.showToast({
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?title: error.msg,
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?duration: 2000,
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?icon: 'none'
?? ??? ??? ??? ??? ??? ??? ??? ??? ?});
?? ??? ??? ??? ??? ??? ??? ??? ?})
?? ??? ??? ??? ??? ??? ??? ?}

?? ??? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ?});
?? ??? ??? ??? ?})
?? ??? ??? ?}
?? ??? ?}
?? ?}

?5、写notification.js文件,必须要按照wxml-to-canvas写生成模板,不然不生效

const wxml = (name, pic, content) => `
<view class="container">
    <text class="content">` + content + `</text>
     <image src="` + pic + `"  class="pic"/>
</view>
`

/**
 * @param {*} screenWidth 屏幕宽度
 * @param {*} canvasWidth  画布宽度
 * @param {*} canvasHeight  画布高度
 * @param {*} numberWidth  数字宽度,动态设置
 * @return {*} 
 */
const style = (screenWidth, canvasWidth, canvasHeight) => {
    return {
        "container": {
            width: canvasWidth,
            height: canvasHeight,
            position: 'relative',
            overflow: 'hidden',
            backgroundColor: '#ffffff',
			padding: '30rpx 20rpx',
        },
        "name": {
            fontSize: 20,
            color: '#333',
            marginLeft: canvasWidth * 0.08,
            width: canvasWidth * 0.84,
            height: screenWidth * 0.18,
            textAlign: 'center',
        },
        "content": {
            fontSize: 14,
            color: '#333',
            width: canvasWidth * 0.84,
            height: screenWidth * 0.84,
            marginLeft: canvasWidth * 0.08,
			marginTop: canvasWidth * 0.08,
        },
        "pic": {
            width: canvasWidth * 0.4,
            height: screenWidth * 0.2,
            marginTop: canvasWidth * 0.1,
            marginLeft: canvasWidth * 0.35,
            marginBottom: canvasWidth * 0.05,
            borderRadius: screenWidth * 0.14,
            overflow: 'hidden',
        },
    }
}

module.exports = {
    wxml,
    style
}