业务场景
使用场景及功能:微信小程序 生成海报图片 分享好友 下载图片
实现效果图
重点步骤拆分
2、用canvas画图,将背景图、费用、二维码等信息绘制在一张图上,其中费用、二维码是动态获取的
4、唤起微信分享功能,实现分享和下载功能
核心代码实现
1、模版部分
需要一个画布dom用来绘制图片,一个用来存放生成图片的dom
答:避免一个页面中使用多个组件引起的canvasId重复问题
<template>
<div class="poster-share__content">
<!-- canvas生成的海报图片 -->
<img
v-if="posterImg"
class="poster-share__content--img"
mode="aspectFit"
:src="posterImg"
>
<!-- 分享海报canvas绘制部分 -->
<canvas
class="poster-share__content--cvs"
:canvas-id="canvasId"
></canvas>
</div>
</template>
2、样式部分
该业务场景下,不能让用户看到画布,但是设置canvas的display为none将不能进行绘制,会报如下错误,导致绘制失败。
.poster-share__content {
position: absolute;
right: -9999px;
top: -9999px;
width: 560px;
height: 852px;
opacity: 0;
z-index: -1;
&--img {
width: 100%;
height: 100%;
}
&--cvs {
width: 100%;
height: 100%;
}
}
3、核心js部分
开始写核心实现啦~
name: 'CpPosterShare',
model: {
prop: 'value',
event: 'update:value',
},
props: {
value: {
type: Boolean,
default: false,
},
config: {
type: Object,
default: ( => ({},
},
},
data ( {
return {
isDraw: false, // 是否开始绘制海报
posterImg: '', // 生成的海报图片地址
canvasId: `canvasId${ Math.random( }`,
screenWidth: null, // 屏幕宽度
}
},
watch: {
value: {
handler (val {
this.isDraw = val
},
immediate: true,
},
isDraw (val {
this.$emit('update:value', val
if (val {
this.init(
}
},
},
首先,我们做的是一个小程序,将图片放在小程序源码中会加大包的体积,需要从网络上下载图片,因此需要封装一个公共的方法来获取图片的信息。Taro提供getImageInfo方法返回图片的原始宽高、本地路径等信息。
// 加载图片
loadImg (src {
return newPromise((resolve, reject => {
Taro.getImageInfo({
src,
}.then((res => {
resolve({ ...res }
}.catch((err => {
reject(err
}
}
}
该业务场景中涉及绘制多张图片,包括背景图片和二维码图片,需要将多张图片都load完成后才能开始绘制。
const promiseParams = [this.loadImg(BgImage, this.loadImg(QRcode]
const promiseAll = Promise.all(promiseParams.map((item =>item.catch(( =>null
promiseAll.then((res => {
this.draw(res
}.catch((err => {
console.log(err
}
开始绘制啦~
ctx.draw(false, ( => {
Taro.canvasToTempFilePath({
canvasId:this.canvasId,
}.then((res => {
this.posterImg = res.tempFilePath
// 唤起分享菜单
this.showShareImageMenu(
}.catch((err => {
console.log('海报生成失败', err
Taro.showToast({
title: '海报生成失败',
icon: 'error',
}
}.finally(( => {
Taro.hideLoading(
this.isDraw = false
}
}
本地图片生成成功后,唤起微信提供的分享菜单弹窗,可以将图片发送给朋友、收藏、保存到相册。Taro提供showShareImageMenu方法唤起分享菜单弹窗,入参为本地图片路径。
showShareImageMenu ( {
if (Taro.showShareImageMenu {
Taro.showShareImageMenu({
path:this.posterImg,
}.then(.catch((err => {
console.log(err
const { errMsg } = err
// 取消操作 errMsg === 'showShareImageMenu:fail cancel'
// 拒绝授权 errMsg: "showShareImageMenu:fail auth deny"
if (errMsg === 'showShareImageMenu:fail auth deny' {
authorize({
scope:'writePhotosAlbum',
showModal:true,
authName:'保存图片到相册',
success: ( => {
this.downloadImg(
},
}
}
}.finally(( => {
this.isDraw = false
}
} else {
Taro.showToast({
title:'小程序版本不支持该功能',
icon:'error',
}
}
}
用户点击发送给朋友,会调起微信对话框,将生成的海报图片粘贴分享给朋友;
点击保存到相册,会唤起保存图片授权弹窗,用户点击允许,会将海报图片保存在本地相册中。
Taro提供Taro.openSetting方法调起小程序设置页面,用户开启“添加到相册”授权后成功后,调用Taro提供的下载图片的方法Taro.saveImageToPhotosAlbum将图片下载到本地。
授权提示弹窗 | 设置页面 | 下载提示 |
/**
* 权限获取流程
* @param scope 权限英文名称
* @param success 授权成功的回调
* @param fail 授权失败的回调
* @param showModal 授权失败是否展示对话框提示
* @param authName 授权失败是否展示对话框提示展示的授权名称
* // 例子:开启用户的相册权限
authorize({
scope: 'writePhotosAlbum',
showModal: true,
authName: '保存图片到相册',
success ( {
console.log('授权成功'
},
}
*/
export async function authorize (options {
const {
scope, success, fail, showModal = false, authName = '',
} = options
try {
const scopeName = `scope.${ scope }`
const auth = await Taro.getSetting(
if (!auth.authSetting[scopeName] {
Taro.authorize({ scope: scopeName }.then((res => {
if (res.errMsg === 'authorize:ok' && success success(
}, ( => {
if (showModal && authName {
Taro.showModal({
title: '授权提示',
content: `您拒绝了${ authName }权限,是否打开设置去授权?`,
}.then((res => {
if (res.confirm {
Taro.openSetting(.then((res2 => {
if (res2.authSetting[scopeName] && success {
success(
} else if (fail {
fail(
}
}
} else {
fail && fail(
}
}.catch((res => {
fail && fail(res
}
} else {
fail && fail(
}
}
} else {
success && success(
}
} catch (err {
fail && fail(err
}
}
至此,具体实现完结撒花~ 可以将组件用到页面中了
组件引用
<poster-share
v-model="draw" // 是否开始绘制海报海报
config="config" // 海报配置信息
/>
问题记录
在开发过程中遇到了一些问题,记录一下
报错信息:"errMsg": "canvasToTempFilePath:fail :create bitmap failed"
作者:京东零售 张梦雨
内容来源:京东云开发者社区