uniapp vue2微信小程序使用wxml-to-canvas

先下载依赖 

npm install --save wxml-to-canvas

下好后在node_modules中找到,创建一个wxcomponents文件夹,将这两个文件放进去。

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

然后在全局插件引入

"globalStyle": {
		"navigationBarTextStyle": "black",
		"navigationBarTitleText": "啊实打实的",
		"navigationBarBackgroundColor": "#fff5ff",
		"backgroundColor": "#F8F8F8",
		"usingComponents": {
			"wxml-to-canvas": "/wxcomponents/wxml-to-canvas/src/index"
		}
	},

ok 配置完成,接下来是在页面模板中写入

<wxml-to-canvas class="widget"></wxml-to-canvas>

然后封装mixin混入

// myMixin.js
const {
    wxml,
    style
} = require('./notification.js')
export default {
    data() {
        return {
            canvasWidth: 320, // 默认canvas宽高
            canvasHeight: 480,
            canvasScreenWidth: null, // 设备宽度
            canvasScreenHeight: null, // 设备宽度
            canvasControlContent: undefined,
            //上个页面用到的图片地址
            canvasTempFile: undefined
        }
    },
    methods: {
        async loadFun() {
            // 获取设备信息
            await wx.getSystemInfo({
                success: (res) => {
                    console.log('res.canvasScreenWidth', res);
                    this.canvasScreenWidth = res.screenWidth
                    this.canvasScreenHeight = 800 //高度建议计算得出或写死。如使用res.screenHeight,文字过长时无法生成(安卓手机,最新鸿蒙系统高度不能超过1000)
                    this.canvasWidth = this.canvasScreenWidth
                    this.canvasHeight = this.canvasScreenHeight
                    setTimeout(() => {
                        console.log('this', this);
                        console.log("this.selectComponent('.widget')", this.selectComponent('.widget'));
                        this.widget = this.selectComponent('.widget');
                        this.canvasControlContent = '你好呀';
                        this.canvasTempFile = 'https://img0.baidu.com/it/u=1715545265,2854041546&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=234'
                        this.download();
                    }, 1000)
                }
            });
        },
        //生成图片
        download() {
            // 数字容器宽度 动态设置 
            setTimeout(() => {
                uni.showLoading({
                    title: '图片生成中...'
                })
                this.renderToCanvas()
            }, 1000)
        },
        renderToCanvas() {
            const _wxml = wxml(this.chosen_chat_list) //调用wxml
            console.log('_wxml', _wxml);
            const _style = style(this.canvasScreenWidth, this.canvasWidth, this.canvasHeight)
            setTimeout(() => {
                console.log('this.widget', this.widget);
                const p1 = this.widget.renderToCanvas({
                    wxml: _wxml,
                    style: _style
                })
                p1.then((res) => {
                    console.log('生成成功', res);
                    uni.hideLoading()
                    this.saveImageToPhotosAlbum();
                }).catch((err) => {
                    console.log('生成失败')
                })
            }, 100)

        },
        //保存图片到本地
        saveImageToPhotosAlbum() {
            uni.showLoading({
                title: '正在保存中...'
            })
            const p2 = this.widget.canvasToTempFilePath()
            console.log('p2', p2);
            let that = this
            p2.then(result => {
                let path = result.tempFilePath
                console.log('path', path);
                uni.saveImageToPhotosAlbum({
                    filePath: path,
                    success: () => {
                        uni.hideLoading()
                        uni.showToast({
                            title: '保存成功,可去手机相册查看',
                            duration: 2000,
                            icon: 'none'
                        });
                        uni.navigateBack();
                    }
                });
            })
        }
    }
}
let aaa = {
    data() {
        return {
            canvasW: 0, // 画布宽
            canvasH: 0, // 画布高
            canvasSystemInfo: {}, // 设备信息
            canvasGoodsImg: {}, // 商品主图信息
            canvasEwmW: 140, // 二维码大小
            canvasTitle: '商品标题商品标题商品标题', // 商品标题
            canvasPrice: '4158.00', // 价格
            canvasName: '浪迹天涯', // 推荐人
            canvasIsShow: false,
            domContent: `
            <div id="source-element">
              <h1 style="color: blue; text-align: center;">这是一个标题</h1>
            </div>
          `,
        };
    },
    methods: {
        async loadFun() {
            // 获取设备信息,主要获取宽度,赋值给canvasW 也就是宽度:100%
            this.canvasSystemInfo = await this.getSystemInfo();
            console.log(this.canvasSystemInfo, '我是设备宽度');
            this.canvasTitle = '我是标题我是标题我是标题我是标题我是标题我是标题我是标题我是标题我是标题我是标题我是标题我是标题我是标题我是标题我是标题我是标题我是标题我是标题我是标题我是标题';
            this.canvasPrice = '价格价格价格';
            // 获取主图,二维码信息
            // let goodsImgUrl = option.goosImg // 主图本地路径,也可以用网络地址
            let goodsImgUrl = 'http://img.touxiangwu.com/2020/3/uq6Bja.jpg' // 头部封面图片
            // shareCodeGet(param).then(res => {	//调接口
            // 	console.log(res, 'resres')
            // let ewmImgUrl = res.data.msg;	//二维码图片地址-从接口取
            // 以下内容放接口里面---下面的内容放接口里面-主要返回二维码地址
            // })
            let that = this
            uni.downloadFile({
                url: goodsImgUrl,
                success: async function (logoRes) {
                    goodsImgUrl = logoRes.tempFilePath
                    var ewmImgUrl = require('@/static/AIFlower.png')
                    // uni.downloadFile({
                    // url: ewmImgUrl,
                    // success: function (logoRes) {
                    // ewmImgUrl = logoRes.tempFilePath
                    that.canvasW = that.canvasSystemInfo.windowWidth; // 画布宽度
                    // 画布高度 = 主图高度+二维码高度 + 文字图片的间距(大概50)
                    that.canvasH = 580 //this.canvasGoodsImg.height + this.canvasEwmW + 10;  
                    uni.showToast({
                        icon: 'loading',
                        mask: true,
                        duration: 10000,
                        title: '海报绘制中',
                    });
                    setTimeout(() => {
                        var ctx = uni.createCanvasContext('myCanvas', that);

                        //列表部分
                        var fontSize = 12;
                        var itemHeight = fontSize + 5;
                        var x = 5;
                        var y = fontSize;

                        ctx.font = fontSize + "px Arial";
                        console.log(' this.chosen_chat_list', that.chosen_chat_list);
                        that.chosen_chat_list.forEach(item => {
                            // 绘制列表项
                            ctx.fillText(item.content, x, y);
                            // 移动到下一个位置
                            y += itemHeight;
                        });
                        //底部
                        ctx.setFontSize(14)
                        ctx.setFillStyle('#b8b8b8')
                        ctx.fillText(
                            '长按或扫描识别二维码' || '', that.canvasW / 2 - that.canvasW / 2.4 / 2,
                            that.canvasW + that.canvasEwmW + 10);

                        // draw方法 把以上内容画到 canvas 中
                        ctx.draw(true, (ret) => {
                            that.canvasIsShow = true // 显示按钮-保存图片到相册
                            uni.showToast({
                                icon: 'success',
                                mask: true,
                                title: '绘制完成',
                            });
                            uni.canvasToTempFilePath({ // 保存canvas为图片
                                canvasId: 'myCanvas',
                                quality: 1,
                                complete: function (res) {
                                    // 在H5平台下,tempFilePath 为 base64, // 图片提示跨域 H5保存base64失败,APP端正常输出临时路径
                                    console.log(res.tempFilePath, '66666666')
                                    // uni.setStorageSync('filePath', res.tempFilePath) //保存临时文件路径到缓存
                                },
                            })
                        });
                    }, 1500)

                    // },
                    // fail:(err)=>{
                    //     console.log('图片下载失败',err);
                    // }
                    // })
                }
            })
        },
        async drawDomToCanvas() {
            // 创建一个不可见的容器并插入DOM内容
            const hiddenContainer = document.getElementById("hidden-container");
            this.domContent = `<view id="source-element" class="chat-body">
            <!-- 聊天记录 -->
            <view class="chat-item" v-for="(item, index) in msgList" :key="index" :id="'index-' + index">
              <!-- 自己发的消息 -->
              <view class="item self" v-if="item.sender == 'user'">
                <!-- 文字内容 -->
                <view class="content right">
                  <!-- 文件列表 -->
                  <view v-if="item.files && item.files.length !== 0">
                    <my-album :FileList="item.files"></my-album>
                    <my-files :FileList="item.files" />
                  </view>
                  <my-text :text="item.content" />
                </view>
              </view>
              <!-- 机器人发的消息 -->
              <view class="item Ai" v-if="item.sender == 'bot'">
                <!-- 头像 -->
                <view class="ai-avatar" v-if="msgList[index-1].sender != 'bot'">
                  <image class="avatar" src="@/static/img/head_ai.png"></image>
                  <view class="text">小花助手</view>
                </view>
                <!-- 文字内容 -->
                <view class="content left">
                  <view v-if="item.files && item.files.length !== 0">
                    <my-loading :FileList="item.files"></my-loading>
                    <my-album :FileList="item.files"></my-album>
                    <my-files :FileList="item.files" />
                  </view>
                  <my-text :loading="loading" :checkboxShow="checkboxShow" @checkFun="checkFun" @clickHandleSend="handleSend" :text="item.content" />
                  <Animation v-show="item.loading" />
                </view>
              </view>
            </view>
          </view>`
            // this.chosen_chat_list.forEach(item => {
            //     // 绘制列表项
            //     ctx.fillText(item.content, x, y);
            //     // 移动到下一个位置
            //     y += itemHeight;
            // });
            hiddenContainer.innerHTML = this.domContent;

            // 获取源元素
            const sourceElement = document.getElementById("source-element");

            // 使用html2canvas将源元素转换为Canvas图像
            const canvas = await html2canvas(sourceElement);

            // 将转换后的Canvas图像绘制到目标Canvas上
            ctx.drawImage(canvas, 0, 0, canvas.width, canvas.height);
        },

        // 获取图片信息
        getImageInfo(image) {
            return new Promise((req, rej) => {
                uni.getImageInfo({
                    src: image,
                    success: function (res) {
                        req(res)
                    },
                });
            })
        },

        // 获取设备信息
        getSystemInfo() {
            return new Promise((req, rej) => {
                uni.getSystemInfo({
                    success: function (res) {
                        req(res)
                    }
                });
            })
        },

        // 保存图片到相册
        async saveImage() {
            let filePath = uni.getStorageSync('filePath') //从缓存中读取临时文件路径		
            console.log(filePath, "filePath")
            uni.saveImageToPhotosAlbum({
                filePath: filePath,
                success() {
                    uni.showToast({
                        title: '图片保存成功',
                        icon: 'none'
                    })
                },
                fail(e) {
                    uni.showToast({
                        title: '图片保存失败',
                        icon: 'none'
                    })
                }
            })
        }
    },
};

然后是封装notification.js

aaa变量是原本别人的方法,上面是我自己写的,目前还有问题,插件官网wxml-to-canvas | 微信开放文档,需要注意样式问题

对象属性值为对应 wxml 标签的 class 驼峰形式。需为每个元素指定 width 和 height 属性,否则会导致布局错误。

存在多个 className 时,位置靠后的优先级更高,子元素会继承父级元素的可继承属性。

元素均为 flex 布局。left/top 等 仅在 absolute 定位下生效

const wxml = (msgList) => {
    // let wml = `<view class="chatBody">
    // ${msgList.map((item, index) => {
    //     if (item.sender == 'user') {
    //         return `<view class="item self" >
    //         <view class="content right">
    //           <view>${item.content}</view>
    //         </view>
    //       </view>`
    //     } else if (item.sender == 'bot') {
    //         return `<view class="item Ai">
    //         ${(index==0||msgList[index - 1].sender != 'bot' )&& `<view class="aiAvatar">
    //         <image class="avatar" src="@/static/img/head_ai.png"></image>
    //         <view class="text">小花助手</view>
    //       </view>`}
    //         <view class="content left">
    //           <view>${item.content}</view>
    //         </view>
    //       </view>`
    //     }
    // })}
    // </view>`
    let wml = `<view class="chatBody">
    ${msgList.map((item, index) => {
            return item.content
    })}
    </view>`
    console.log('wml', wml);
    return wml
}


// ${msgList.map((item, index) => {
//     if (item.sender == 'user') {
//         return `<view class="item self" >
//         <view class="content right">
//           <view>${item.content}</view>
//         </view>
//       </view>`
//     } else if (item.sender == 'bot') {
//         return `<view class="item Ai">
//         ${(index==0||msgList[index - 1].sender != 'bot' )&& `<view class="ai-avatar">
//         <image class="avatar" src="@/static/img/head_ai.png"></image>
//         <view class="text">小花助手</view>
//       </view>`}
//         <view class="content left">
//           <view>${item.content}</view>
//         </view>
//       </view>`
//     }
// })}

let qita = `
<view v-if="item.files && item.files.length !== 0">
<my-album :FileList="item.files"></my-album>
<my-files :FileList="item.files" />
</view>
<view v-if="item.files && item.files.length !== 0">
<my-album :FileList="item.files"></my-album>
<my-files :FileList="item.files" />
</view>
`

/**
 * @param {*} screenWidth 屏幕宽度
 * @param {*} canvasWidth  画布宽度
 * @param {*} canvasHeight  画布高度
 * @param {*} numberWidth  数字宽度,动态设置
 * @return {*} 
 */
const style = (screenWidth, canvasWidth, canvasHeight) => {
    return {
        "chatBody": {
            width: screenWidth,
            height: canvasHeight,
            // backgroundColor: `linear-gradient(
            //     145deg,
            //     rgba(76, 216, 251, 0.5) 0%,
            //     rgba(255, 255, 255, 0.5) 35%,
            //     rgba(255, 255, 255, 0.5) 26%,
            //     rgba(254, 235, 255, 0.5) 50%
            //   )
            //   bottom right / 50% 50% no-repeat,
            // linear-gradient(
            //     215deg,
            //     rgba(76, 216, 251, 0.5) 0%,
            //     rgba(255, 255, 255, 0.5) 35%,
            //     rgba(255, 255, 255, 0.5) 26%,
            //     rgba(254, 235, 255, 0.5) 50%
            //   )
            //   bottom left / 50% 50% no-repeat,
            // linear-gradient(
            //     325deg,
            //     rgba(76, 216, 251, 0.5) 0%,
            //     rgba(255, 255, 255, 0.5) 35%,
            //     rgba(255, 255, 255, 0.5) 26%,
            //     rgba(254, 235, 255, 0.5) 50%
            //   )
            //   top left / 50% 50% no-repeat,
            // linear-gradient(
            //     35deg,
            //     rgba(76, 216, 251, 0.5) 0%,
            //     rgba(255, 255, 255, 0.5) 35%,
            //     rgba(255, 255, 255, 0.5) 26%,
            //     rgba(254, 235, 255, 0.5) 50%
            //   )
            //   top right / 50% 50% no-repeat,
            // #fff`,
            backgroundColor:"#fff",
            color: '#333',
            fontSize: 14
        },
        "item": {
            boxSizing: 'border-box',
            width: screenWidth,
            height: screenWidth*0.3,//测试
            padding: '12rpx 20rpx',
            display: 'flex',
            flexWrap: 'wrap'
        },
        "self": {
            justifyContent: 'flex-end',
            flex: '1'
        },
        "aiAvatar": {
            width: screenWidth,
            height: screenWidth*0.3,//测试
            display: 'flex',
        },
        "avatar": {
            width: screenWidth*0.1,
            height: screenWidth*0.1,
            display: 'flex',
            justifyContent: 'center',
            borderRadius: '50%',
            overflow: 'hidden',
            margin: '0 6px 6px 0'
        },
        "text": {
            width: screenWidth,
            height: screenWidth*0.1,
            lineHeight: screenWidth*0.1,
            fontSize: 14,
            background: 'linear-gradient(90deg, #fff 0%, #f306fb 0.01%, #0098f0 93.75%)',
            webkitBackgroundClip: 'text',
            webkitTextFillColor: 'transparent',
        },
        "content": {
            width: screenWidth,//测试
            height: screenWidth*1,//测试
            display: 'inline-block',
            wordWrap: 'break-word',
            padding: '12px',
            borderRadius: '16px',
            fontSize: 14,
            fontFamily: 'PingFang SC',
            fontWeight: '400',
            color: '#333333',
            lineHeight: '20px'
        },
        "left": {
            backgroundColor: '#ffffff',
            borderTopLeftRadius: ' 4px !important'
        },
        "right": {
            backgroundColor: '#c2dcff',
            borderTopRightRadius: '4px !important'
        },

        // "container-mm": {
        //     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
}

在页面中使用 混入方法

import sharrChatRecord from "./sharrChatRecord.js";
mixins: [sharrChatRecord], 

  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在uniapp中开发微信小程序使用mockjs模拟请求,可以按照以下步骤进行操作: 1. 安装mockjs 在项目根目录下执行以下命令: ``` npm install mockjs -D ``` 2. 创建mock数据 在项目根目录下创建一个mock目录,并在其中创建一个数据文件,例如`data.js`。在`data.js`中编写mock数据,例如: ``` import Mock from 'mockjs' Mock.mock('/api/login', 'post', { code: 200, message: '登录成功', data: { token: '1234567890' } }) ``` 以上代码模拟了一个登录接口,返回了一个token。 3. 在请求拦截器中使用mockjs 在uniapp中,可以在`App.vue`或者`main.js`中的请求拦截器中使用mockjs。例如: ``` import Mock from 'mockjs' import Vue from 'vue' Vue.prototype.$http.interceptors.request.use( config => { if (process.env.NODE_ENV === 'development') { Mock.setup({ timeout: '300-600' }) Mock.mock('/api/login', 'post', { code: 200, message: '登录成功', data: { token: '1234567890' } }) } return config }, err => { return Promise.reject(err) } ) ``` 以上代码将mock数据绑定到了`/api/login`接口上,并设置了超时时间。 4. 使用mock数据进行测试 在开发过程中,可以先使用mock数据进行接口测试。测试通过后,再使用实际接口。例如: ``` export function login(params) { if (process.env.NODE_ENV === 'development') { return Vue.prototype.$http.post('/api/login', params) } else { return Vue.prototype.$http.post('/login', params) } } ``` 以上代码在开发环境中使用mock数据,生产环境中使用实际接口。 总结: 以上就是在uniapp中开发微信小程序使用mockjs模拟请求的步骤,可以方便开发人员进行接口测试,提高开发效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值