1,首先说明一下,我之前遇到一个需求 让我点击一个按钮可以对着当前整个页面进行长截图
这个功能折磨了我一个星期 之后我去问了某宝的人 百分之70说 做不出来,剩下的开会后收我一万元,我就呵呵呵了 于是我苦心钻研 后 借助一个插件(自己修改了些代码)完成了这一个功能,分享给大家----前人栽树 后人乘凉!
---------------------------------------------------------------------------------------------------------------------------------
正式开始
第一步
去uniapp插件市场下载导入到你的项目中(感谢这位插件作者)
tk-view2canvas 页面截屏组件 - DCloud 插件市场
安装完成后 里面的代码需要改写--以下是我的改写后的 你可以直接复制粘贴代替掉他的
<template>
<view>
</view>
</template>
<script>
let promiseIndex = 0
let promiseArray = []
let imageArray = []
let imageIndex = 0
export default {
name: "kt-view2canvas",
data() {
return {
};
},
props: {
canvasWidth: {
type: Number,
default: 1080
},
canvasHeight: {
type: Number,
default: 2500
}
},
methods: {
//rpx转换为px的工具函数
rpxtopx(rpx) {
let deviceWidth = wx.getSystemInfoSync().windowWidth; //获取设备屏幕宽度
let px = (deviceWidth / 750) * Number(rpx)
return Math.floor(px);
},
drawCanvas(arrayInfo) {
promiseIndex = 0
promiseArray = []
imageArray = []
imageIndex = 0
uni.showLoading({
title: '保存中...'
})
// 0.创建canvas及ctx,并获取屏幕的dpr
const canvas = wx.createOffscreenCanvas({
type: '2d',
width: this.canvasWidth,
height: this.canvasHeight
})
const ctx = canvas.getContext('2d')
const dpr = uni.getWindowInfo().pixelRatio
// 1.根据数组数量创建promise数组
for (let i = 0; i < arrayInfo.length; i++) {
promiseArray.push(promiseIndex)
promiseIndex++
}
// 2.根据数组给promise数组赋值
let that = this
for (let i = 0; i < arrayInfo.length; i++) {
promiseArray[i] = new Promise(function(resolve, reject) {
if (arrayInfo[i].type == 'text') {
resolve()
} else if (arrayInfo[i].type == 'view') {
resolve()
} else if (arrayInfo[i].type == 'image') {
let img = canvas.createImage()
img.src = arrayInfo[i].src
img.onload = function() {
imageArray.push(img)
resolve()
}
img.src = arrayInfo[i].src + `?${new Date().getTime()}`
}
})
}
// 3.异步全部加载完成后,绘制图片
let p = Promise.all(promiseArray)
p.then(function() {
//根据数组顺序绘制图片
for (let i = 0; i < arrayInfo.length; i++) {
if (arrayInfo[i].type == 'text') {
ctx.fillStyle = arrayInfo[i].color
ctx.font = that.rpxtopx(arrayInfo[i].size) * dpr + 'px sans-serif'
ctx.textBaseline = 'top'
ctx.fillText(arrayInfo[i].word, arrayInfo[i].posX * dpr, (arrayInfo[i].posY + that
.rpxtopx(20)) * dpr)
} else if (arrayInfo[i].type == 'view') {
ctx.fillStyle = arrayInfo[i].bgColor
ctx.fillRect(arrayInfo[i].posX * dpr, arrayInfo[i].posY * dpr, arrayInfo[i].width *
dpr, arrayInfo[i].height * dpr)
} else if (arrayInfo[i].type == 'image') {
ctx.drawImage(imageArray[imageIndex], arrayInfo[i].posX * dpr, arrayInfo[i].posY * dpr,
arrayInfo[i].width * dpr, arrayInfo[i].height * dpr)
imageIndex++
}
}
const fileData = canvas.toDataURL()
const fs = uni.getFileSystemManager()
const path = `${wx.env.USER_DATA_PATH}/` + new Date().getTime() + `hello.png`
//数据归零
promiseIndex = 0
promiseArray = []
imageArray = []
imageIndex = 0
fs.writeFile({
filePath: path,
data: fileData.replace(/^data:image\/\w+;base64,/, ""),
encoding: 'base64',
success(res) {
uni.showShareImageMenu({
path: path,
success: res => {
console.log(res);
}
})
},
fail(res) {
console.error(res)
},
complete() {
uni.hideLoading()
}
})
})
}
}
}
</script>
<style>
</style>
第二步
去到你需要截图的页面 引入(如下图)
* canvasWidth 是你画布的宽度 ---- canvasHeight 是你画布的高度(他们决定着你画出来图片的宽高 后期可以自行调整)
第三步
把canvasWidth canvasHeight 写进data中
第四步
建立触发事件--我这里就拿点击事件举例子
view中
<button @click="toCanvas" /> 这是触发 图片生成的事件
JavaScript中
toCanvas() {
let that = this
arrayInfo = []
// 1.先查询要绘制的view,image,text相关属性数据
uni.createSelectorQuery().selectAll('.queryInfo').boundingClientRect().exec((res) => {
// console.log('获取到信息:', res[0])
let resArray = res[0]
for (let i = 0; i < resArray.length; i++) {
//1.判断查询到的组件类别,如果是view类,就按照view对应的格式将创建的对象添加到数组中
if (resArray[i].dataset.type == 'view') {
// console.log('view')
let bgColor = resArray[i].dataset.bgcolor
let width = resArray[i].width
let height = resArray[i].height
let posX = resArray[i].left
let posY = resArray[i].top
arrayInfo.push({
type: 'view',
width: width,
height: height,
bgColor: bgColor,
posX: posX,
posY: posY
})
} //2.判断查询到的组件类别,如果是image类,就按照image对应的格式将创建的对象添加到数组中
else if (resArray[i].dataset.type == 'image') {
// console.log('image')
let type = 'image'
let src = resArray[i].dataset.src
let posX = resArray[i].left
let posY = resArray[i].top
let width = resArray[i].width
let height = resArray[i].height
arrayInfo.push({
type: 'image',
src: src,
width: width,
height: height,
posX: posX,
posY: posY
})
} //3.判断查询到的组件类别,如果是text类,就按照text对应的格式将创建的对象添加到数组中
else if (resArray[i].dataset.type == 'text') {
// console.log('text')
let type = 'text'
let color = resArray[i].dataset.color
let word = resArray[i].dataset.word
let size = resArray[i].dataset.size
let posX = resArray[i].left
let posY = resArray[i].top
arrayInfo.push({
type: 'text',
color: color,
word: word,
size: size,
posX: posX,
posY: posY
})
}
}
//查询完毕后,也就创建好了arrayInfo数组,下面将arrayInfo数组作为参数,传给组件的drawCanvas()方法
that.$refs.tkCanvas.drawCanvas(arrayInfo)
})
},
事件里面的代码你也可以先复制粘贴我的 后面你自己慢慢研究
第五步(最繁琐的一步-加油你快成功了)
开始 设置你要绘制的当前页的内容(需要出现在图片上的内容就 设置 不需要的就不设置,不设置的就不会在图片上出现)
1,只要是view 就在盒子里加上 并且 在class中必须加入 queryInfo
(需要出现在图片上的内容就加 不需要的不加 你之前有的class内容 不动他)
<view class="queryInfo" data-type="view" />---data-type="view" 是他是什么类型的盒子必写
2,颜色设置 -- data-bgcolor="#ffffff" data-color ="#000"
<view class="queryInfo" data-type="view" data-bgcolor="#ffffff" data-color ="#000" />
3,所有文字必须用text包裹起来 且和上面一样 clas,也是必须加 还有内容要放在data中切记
<text class="queryInfo" data-type="text" :data-word="xuexiaoname" data-font-weight="800" data-margin-top="60" data-color="#000" data-size="45">{{xuexiaoname}}</text>
---样式前面必须加data- text盒子 必须加data-type="text" 文字内容必须在data中 要配合:data-word="xuexiaoname" 切记不然没办法画出来
4,图片内容 image
<image class="queryInfo" data-type="image" :data-src="item" :src="item" mode=""></image>
:data-src="这里是图片地址 可以是本地 也可以是 网络(我这里前面遍历了你随意)"
:src="和上面一样"
图片就写 data-type="image" 而且class里面的 queryInfo不能少
到这里就结束了,切记 不需要现实的 就原封不动不管他 需要显示在图片上上的内容 就按上面的操作,生成的图片大小不合适 可以调整data中的 canvasWidth canvasHeight。
如果您觉得有用 麻烦帮我点个赞收藏一下,还是老话--前人栽树 后人乘凉