在使用uni-app 开发的过程中有没有遇到 无法使用html2canvas生成图片的问题呢?那么通过这篇文章,我们来记录下如何在uniapp生成画布图片的。
首先需要在你的uni-app项目中安装 html2canvas 插件
如果项目没有package.json 文件,那么就需要先 npm init 初始化下,那么这个文件就会出来了
npm install html2canvas -D
在需要生成图片的页面中引入 html2canvas 插件
不过此时需要在 页面中新建一个 script 节点,将 lang 属性设置为renderjs,代码如下:
<script>
export default {
data() {
return {};
}
};
</script>
// 在这里新增一个 script 节点 用于在页面中使用dom
<script lang="renderjs" module="canvasImage">
import html2canvas from 'html2canvas'
export default {
}
</script>
如对 renderjs 不了解,可看下uniapp 官网的说明,链接:https://uniapp.dcloud.io/frame?id=renderjs
编写生成图片的代码
<script lang="renderjs" module="canvasImage">
import html2canvas from 'html2canvas'
export default {
methods: {
// 生成图片需要调用的方法
generateImage(e, ownerFun) {
ownerFun.callMethod('_showLoading','正在生成图片') // 生成图片的 loading 提示
setTimeout(() => {
const dom = document.getElementById('pagePoster') // 需要生成图片内容的 dom 节点
html2canvas(dom, {
width: dom.clientWidth, //dom 原始宽度
height: dom.clientHeight,
scrollY: 0, // html2canvas默认绘制视图内的页面,需要把scrollY,scrollX设置为0
scrollX: 0,
useCORS: true, //支持跨域
// scale: 2, // 设置生成图片的像素比例,默认是1,如果生成的图片模糊的话可以开启该配置项
}).then((canvas) => {
// 生成成功
// html2canvas 生成成功的图片链接需要转成 base64位的url
ownerFun.callMethod('receiveRenderData', canvas.toDataURL('image/png'))
}).catch(err=>{
// 生成失败 弹出提示弹窗
ownerFun.callMethod('_errAlert',`【生成图片失败,请重试】${err}`)
})
}, 300)
}
}
}
</script>
完整案例代码
说明:在案例代码中,有使用到 imageTools.js 的插件,这是用来做base64图片链接转化用的(可以通过后方的链接去插件市场下载,如果您是位大佬,可以自己手写相关的转换base64的功能代码)。可以在https://ext.dcloud.net.cn/plugin?id=123 中下载imageTools.js引入到自己的项目中。【需要用到下方的功能才需要引入,否则不需要引入】
如:
- 在生成图片的模版中使用本地图片,则就要将本地本地资源图片转成base64位,才能在app端中进行生成图片(h5不需要转base64也可以生成)。如果您使用的是网络资源图片则不需要转base64这个步骤.
- 在app端中将图片保存到手机相册功能:需要将生成画布的base64位的图片url转成临时文件路径,这样才能保存到手机相册。而H5可以通过长按图片来进行保存(我用的是ios手机来测试,安卓的没有测试过),微信小程序的话目前没有做处理,不过我是打算通过 webview 来引用 H5 的页面来进行长按保存图片。
<!-- 为了解决在安卓手机(或部分手机)中生成画布后里面的图片模糊问题,那么建议将该页面所有的 image 标签改为 img 标签,这样兼容性会更好些! -->
<template>
<view class="html2Canvas">
<!-- 需要生成图片的模板 -->
<view class="canvas-module" id="pagePoster">
<view class="user-info">
<view class="user-img">
<img :src="userImage" alt="" />
</view>
<view class="user-detail">
<view class="user-name">测试</view>
<view class="user-num">12345678901</view>
</view>
</view>
<view class="section">
<view class="title">简单介绍</view>
<view class="detail-text">
你好啊的客户看见阿斯加德很快就哈介绍的客户看见阿斯加德很快就哈介绍的客户看见阿斯加德很快就哈介绍的客户看见阿斯加德很快就哈介绍的客户看见
</view>
</view>
</view>
<view class="generate-image" @click="canvasImage.generateImage">生成图片</view>
<!-- 生成的图片 -->
<view v-if="posterUrl" class="section-result">
<view class="title">生成的图片</view>
<!-- H5采用长按保存图片,app就可以通过按钮保存或分享,微信小程序需要连接到H5再进行长按保存 -->
<!-- 图片使用 img 标签会好些,可以更好的兼容base64位图片连接的显示 -->
<img class="image" :src="posterUrl" alt="" @load="_hideLoading" />
<!-- #ifdef APP-PLUS -->
<view class="generate-image" @click="loadBase64Url">保存图片到手机</view>
<!-- #endif -->
</view>
</view>
</template>
<script>
import { pathToBase64, base64ToPath } from '../../common/js/imageTools.js';
export default {
data() {
return {
posterUrl: '', // 生成画布的图片
userImage: ''// 本地头像图片
};
},
onLoad() {
this.turnBase64Image('./../../static/images/wnm.jpg', 'userImage');
},
methods: {
/* 将base64 位的图片路径转换为 临时路径 */
loadBase64Url() {
const imageStr = this.posterUrl;
base64ToPath(imageStr)
.then(path => {
this.saveImage(path);
})
.catch(error => {
console.error('临时路径转换出错了:', error);
});
},
// 保存图片到手机相册
saveImage(filePath) {
uni.saveImageToPhotosAlbum({
filePath, // 需要临时文件路径,base64无法保存
success: () => {
this._showToast('保存图片成功');
},
fail: () => {
this._showToast('保存失败,请重试');
}
});
},
// 将图片转为base 64 位url
turnBase64Image(img, key) {
uni.getImageInfo({
src: img,
success: image => {
pathToBase64(image.path)
.then(base64 => {
this[key] = base64;
})
.catch(error => {
console.log('转换失败:', error);
});
},
fail: err => {
console.log('将本地图片转为base 64报错:', err);
}
});
},
// 获取生成的base64 图片路径
receiveRenderData(val) {
this.posterUrl = val.replace(/[
]/g, ''); // 去除base64位中的空格
},
// 显示loading
_showLoading(str) {
this.posterUrl = '';
uni.showLoading({
title: str
});
},
// 隐藏loading
_hideLoading() {
uni.hideLoading();
// #ifdef H5
this._showToast('长按保存图片');
// #endif
},
// 报错alert
_errAlert(content) {
uni.showModal({
title: '提示',
content: content
});
},
// 提示弹窗
_showToast(msg) {
uni.showToast({
title: msg,
icon: 'none'
});
}
}
};
</script>
<script lang="renderjs" module="canvasImage">
import html2canvas from 'html2canvas'
export default {
methods: {
// 生成图片需要调用的方法
generateImage(e, ownerFun) {
ownerFun.callMethod('_showLoading','正在生成图片') // 生成图片的 loading 提示
setTimeout(() => {
const dom = document.getElementById('pagePoster') // 需要生成图片内容的 dom 节点
html2canvas(dom, {
width: dom.clientWidth, //dom 原始宽度
height: dom.clientHeight,
scrollY: 0, // html2canvas默认绘制视图内的页面,需要把scrollY,scrollX设置为0
scrollX: 0,
useCORS: true, //支持跨域
// scale: 2, // 设置生成图片的像素比例,默认是1,如果生成的图片模糊的话可以开启该配置项
}).then((canvas) => {
// 生成成功
// html2canvas 生成成功的图片链接需要转成 base64位的url
ownerFun.callMethod('receiveRenderData', canvas.toDataURL('image/png'))
}).catch(err=>{
// 生成失败 弹出提示弹窗
ownerFun.callMethod('_errAlert',`【生成图片失败,请重试】${err}`)
})
}, 300)
}
}
}
</script>
<style lang="scss" scoped>
image,img {
width: 100%;
height: 100%;
}
.html2Canvas {
.canvas-module {
margin: 30rpx 30rpx 0;
padding: 0 30rpx;
box-shadow: 0 0 8rpx 0 rgba(56, 56, 56, 0.14);
border-radius: 12rpx;
background-color: #f6f6f6;
.user-info {
display: flex;
align-items: center;
padding: 30rpx 0;
border-bottom: 1rpx solid #e5e5e5;
.user-img {
width: 140rpx;
height: 140rpx;
border-radius: 50%;
overflow: hidden;
}
.user-detail {
margin-left: 20rpx;
.user-name {
font-size: 38rpx;
color: #333;
font-weight: bold;
}
.user-num {
margin-top: 10rpx;
font-size: 32rpx;
color: #999;
}
}
}
.section {
padding: 30rpx 0;
.title {
font-size: 36rpx;
font-weight: bold;
}
.detail-text {
font-size: 28rpx;
line-height: 1.4;
color: #666;
margin-top: 12rpx;
text-indent: 2em;
}
}
}
.generate-image {
height: 98rpx;
margin: 30rpx 30rpx;
background-color: #41b783;
font-size: 32rpx;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
border-radius: 12rpx;
}
.section-result {
margin: 30rpx 30rpx;
.title {
font-size: 36rpx;
font-weight: bold;
margin-bottom: 30rpx;
}
}
}
</style>
最终显示结果
app显示出来的结果