1,安装html2canvas
npm install html2canvas --save
2,在需要的页面引入
import html2canvas from 'html2canvas'
3,使用
html2canvas(document.body).then((canvas)=> {
document.body.appendChild(canvas);
});
4,如果要下载的话,可以使用a标签来下载,但是ios和微信不支持
<a href=""
download="你的账单.png"
id="downimg"
style="display:none">保存账单</a>
js:这里我模拟了a标签的点击
let downbtn = document.getElementById('downimg')
html2canvas(document.getElementById('ten')).then((canvas) => {
downbtn.href = canvas.toDataURL('image/png')
}).then(() => {
downbtn.click()
})
5,既然微信和ios不支持下载图片,那怎么解决呢,可以显示出图片,然后提示让用户自己去保存
let ele = document.getElementById('ten')
html2canvas(ele).then((canvas) => {
var canvimg = document.createElement('img')
canvimg.src = canvas.toDataURL('image/png')
canvimg.style.width = '100%'
canvimg.style.height = '100%'
document.getElementById('ten').appendChild(canvimg)
alert('账单已生成\n请长按保存账单')
})
示例
<template>
<view class="content" >
<view ref="imageWrapper" id="poster">
<view class="viewImg">
<view class="box">
<view class="title">
<text>{{articleMes.title}}</text>
</view>
<view class="flex-space author">
<text>作者:{{articleMes.author}}</text>
<view class="date">
<text class="num">{{articleMes.browseNum}}次浏览</text> |
<text class="num">{{articleMes.createTime}}</text>
</view>
</view>
<view class="stance">
<!-- {{articleMes.content}} -->
<view v-html="articleMes.content"></view>
<image class="img_" :src="articleMes.cover" mode="widthFix"></image>
</view>
<view class="codeImg">
<canvas class="code" canvas-id="couponQrcode"></canvas>
<!-- <image class="code" src="@/static/code.jpg" mode=""></image> -->
</view>
</view>
</view>
</view>
<view class="saveBtn" @click="capture()">
<text>保存海报</text>
</view>
</view>
</template>
<script>
import html2canvas from "html2canvas"
import {
articleDetail,
} from '@/api/index/user.js'
const qrCode = require('@/common//weapp-qrcode.js')
export default{
data(){
return {
base64:'',
id:'',
articleMes:{}
}
},
onLoad(options) {
let that = this
that.id = options.id
that.getArticalDetail()
setTimeout(() => {
that.couponQrCode()
}, 50)
},
methods:{
couponQrCode() {
new qrCode('couponQrcode', {
text: "https://www.baidu.com/baidu?tn=monline_3_dg&ie=utf-8&wd=csdn",
width: 125,
height: 125,
colorDark: "#333333",
colorLight: "#FFFFFF",
correctLevel: qrCode.CorrectLevel.H,
src: require('@/pagesA/static/images/rank/qiye.png')
})
},
// 获取文章详情
getArticalDetail(){
let that = this
let data = {
id:that.id,
userId:uni.getStorageSync('userInfo').id
}
articleDetail(data).then(res => {
that.articleMes = res.data
})
},
capture() {
// var dom = document.querySelector('#poster')
html2canvas(this.refs.imageWrapper).then((canvas) => {
// 将生产的canvas转为base64图片
this.base64 = canvas.toDataURL('image/png')
this.saveImg(this.base64)
});
},
saveImg(url){
uni.downloadFile({
url,
success: (res) => {
// 获取到图片本地地址后再保存图片到相册
uni.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success: () => {
uni.showToast({
title: "保存成功!",
});
},
fail: () => {
uni.showToast({
title: "保存失败",
});
},
});
},
});
}
}
}
</script>
<style lang="scss">
page{
background-color: #FB9571;
}
.content{
padding-bottom: 100rpx;
#poster{
background: url('@/pagesA/static/images/operate/poster-bgc.jpg') no-repeat;
background-size: 100%;
padding: 40rpx 20rpx 100rpx;
.viewImg{
padding: 20rpx;
width: 85%;
margin: 0 auto;
border-radius: 30rpx;
background: rgba(255,255,255,.36);
}
}
.box{
background: #fff;
border-radius: 30rpx;
padding: 30rpx;
}
.title{
font-weight: bold;
color: #333;
font-size: 38rpx;
margin-bottom: 20rpx;
}
.author{
font-size: 28rpx;
border-bottom: 2rpx solid #F8F8F8;
padding-bottom: 15rpx;
white-space: nowrap;
}
.date{
color: #AAAAAA;
font-size: 26rpx;
.num{
margin: 0 15rpx;
}
}
.stance{
padding: 40rpx 0;
white-space: pre-wrap;
font-size: 30rpx;
.img_{
display: block;
margin: 20rpx auto 0;
max-width: 100%;
// height: auto;
}
}
.codeImg{
border-top: 2rpx solid #f5f5f5;
.code{
width: 250rpx;
height: 250rpx;
display: block;
margin: 30rpx auto;
}
}
}
.saveBtn{
background-color: #DD490A;
color: #fff;
border-radius: 50rpx;
display: block;
text-align: center;
padding: 26rpx 0;
font-size: 30rpx;
width: 85%;
margin: 0 auto;
box-shadow: 0 0 8rpx #dd490a;
}
</style>
**
**
示例,页面
<template>
<view class="">
<canvas style='width:375px;height:580px' canvas-id="canvasboxid" id="canvasboxid"></canvas>
<view class="btnbox" @click="savePic">
保存
</view>
</view>
</template>
<script>
export default {
data() {
return {
tempFilePath:''
}
},
onReady() {
this.capture()
},
onload() {
// this.capture()
},
methods: {
capture() {
console.log('canvas绘制文本==================================')
// canvas绘制文本
const ctx = uni.createCanvasContext('canvasboxid', this)
// canvas布局
ctx.setFontSize(20)
ctx.setTextAlign('center')
ctx.fillText('缴费凭证', 162, 40)
ctx.setFillStyle('#f95455')
ctx.fillText('¥' + 123 + '.00', 162, 75)
ctx.setFontSize(14)
ctx.setFillStyle('#999999')
ctx.fillText('缴费类型', 95, 100)
ctx.fillText('缴费方式', 230, 100)
// 绘制矩形,在矩形中添加文本
ctx.setFillStyle('rgba(225,225,225,0)')
ctx.setFontSize(11)
ctx.strokeStyle = "#333333";
ctx.moveTo(24, 120)
ctx.lineTo(172, 120)
ctx.lineTo(172, 150)
ctx.lineTo(24, 150)
ctx.lineTo(24, 120)
ctx.closePath();
ctx.fill();
this.drawText(ctx, '文字描述王佳家', 90, 120, 20, 160)
ctx.setFillStyle('#333333')
ctx.setFontSize(13)
ctx.fillText('现金缴费', 230, 120)
ctx.setFontSize(14)
ctx.setTextAlign('left')
ctx.setFillStyle('#999999')
ctx.fillText('姓名', 25, 165)
ctx.setTextAlign('right')
ctx.setFillStyle('#333333')
ctx.fillText('现金缴费啦啦啦啦', 300, 165)
ctx.setTextAlign('left')
ctx.setFillStyle('#999999')
ctx.fillText('手机号', 25, 195)
ctx.setTextAlign('right')
ctx.setFillStyle('#333333')
ctx.fillText('15093417544', 300, 195)
ctx.setTextAlign('left')
ctx.setFillStyle('#999999')
ctx.fillText('房号', 25, 225)
ctx.setTextAlign('right')
ctx.setFillStyle('#333333')
ctx.fillText('1509341', 300, 225)
ctx.setTextAlign('left')
ctx.setFillStyle('#999999')
ctx.fillText('收费单位', 25, 255)
ctx.setTextAlign('right')
ctx.setFillStyle('#333333')
ctx.fillText('国网晋中电力有限公司', 300, 255)
// 绘制虚线
ctx.setLineDash([2, 4], 5);
ctx.beginPath();
ctx.moveTo(25, 280);
ctx.lineTo(300, 280);
ctx.stroke();
ctx.setTextAlign('left')
ctx.setFillStyle('#999999')
ctx.fillText('付款时间', 25, 310)
ctx.setTextAlign('right')
ctx.setFillStyle('#333333')
ctx.fillText('支付时间2022', 300, 310)
ctx.setTextAlign('left')
ctx.setFillStyle('#999999')
ctx.fillText('流水号', 25, 340)
ctx.setTextAlign('right')
ctx.setFillStyle('#333333')
ctx.fillText('id123', 300, 340)
// canvas画布转为图片 ,有时draw调用不成功,写了个定时器
ctx.draw(setTimeout(() => {
uni.canvasToTempFilePath({
x: 0,
y: 0,
width: 325,
height: 375,
destWidth: 325,
destHeight: 375,
fileType: 'jpg',
canvasId: 'canvasboxid',
success: (res) => {
uni.hideLoading()
// // 保存当前绘制图片
this.tempFilePath = res.tempFilePath
},
fail: function(err) {
console.log(err, '图片生成失败')
}
})
}, 500))
},
// 控制绘制文本换行,百度CV的
drawText: function(ctx, str, leftWidth, initHeight, titleHeight, canvasWidth) {
var lineWidth = 0;
var lastSubStrIndex = 0; //每次开始截取的字符串的索引
for (let i = 0; i < str.length; i++) {
lineWidth += ctx.measureText(str[i]).width;
if (lineWidth > canvasWidth) {
//因为我这个在矩形中的文本进行的换行,用的ctx.strokeText,不行用在矩形中添加文本的用ctx.fillText
ctx.strokeText(str.substring(lastSubStrIndex, i), leftWidth, initHeight); //绘制截取部分
initHeight += 11; //11为字体的高度
lineWidth = 0;
lastSubStrIndex = i;
titleHeight += 30;
}
if (i == str.length - 1) { //绘制剩余部分
ctx.strokeText(str.substring(lastSubStrIndex, i + 1), leftWidth, initHeight);
}
}
// 标题border-bottom 线距顶部距离
titleHeight = titleHeight + 10;
return titleHeight
},
// 保存图片到本地,下面保存到手机百度CV的
savePic() {
uni.getSetting({
//获取用户的当前设置
success: res => {
if (res.authSetting['scope.writePhotosAlbum']) {
//验证用户是否授权可以访问相册
uni.saveImageToPhotosAlbum({
filePath: this.tempFilePath,
success: function(res2) {
uni.hideLoading();
uni.showToast({
title: '保存成功,请从相册选择再分享',
icon: 'none',
duration: 2000
});
},
fail: function(err) {
uni.hideLoading();
uni.showToast({
title: '保存失败',
icon: 'none',
duration: 2000
});
}
});
} else {
uni.authorize({
//如果没有授权,向用户发起请求
scope: 'scope.writePhotosAlbum',
success: () => {
// this.saveImageToPhotosAlbum();
console.log('发起请求')
uni.showToast({
title: '请打开保存相册权限,再点击保存相册分享1111',
icon: 'none',
duration: 2000
});
setTimeout(() => {
uni.openSetting({
//调起客户端小程序设置界面,让用户开启访问相册
success: res2 => {
// console.log(res2.authSetting)
}
});
}, 2000);
},
fail: () => {
uni.showToast({
title: '请打开保存相册权限,再点击保存相册分享',
icon: 'none',
duration: 2000
});
setTimeout(() => {
uni.openSetting({
//调起客户端小程序设置界面,让用户开启访问相册
success: res2 => {
// console.log(res2.authSetting)
}
});
}, 2000);
}
});
}
}
});
},
}
}
</script>
<style>
.btnbox{
margin: 0 auto;
width: 80%;
height: 80rpx;
line-height: 80rpx;
text-align: center;
border: 1rpx solid #ccc;
border-radius: 10rpx;
}
</style>