需求:
小程式實現生成海報功能,海報上面加頭像和姓名以及二維碼
實現:Taro 小程式(js + redux + sass)
import { ComponentClass } from 'react'
import Taro, { Component } from '@tarojs/taro'
import { View, Image, Text, Video, Button } from '@tarojs/components'
import { connect } from '@tarojs/redux'
import {
getUserInfoApi,
getLittleAppQRCodeApi
} from '../../service/api.service';
import './collagePoster.scss'
@connect(({ globalData, authData, payInfoData }) => ({
globalData,
authData,
payInfoData
}))
class collagePoster extends Component {
config = {
navigationBarTitleText: '生成海報',
pages: [
'pages/collagePoster/collagePoster'
]
};
constructor(props) {
super(props);
this.state = {
headPhoto: '', // 頭像
avatorSrc: '',
studentName: '', // 姓名
bgImg: 'https://appd.knowbox.cn/ss/miniapp/shareImg/collagePosterBg.png', // 背景圖
bgSrc: '',
codeImg: '', // 二維碼
codeSrc: '',
shareText: '給我家孩子報了程式設計課,在家就能上課,大廠課程品質有保障,有一起參團的不?5節課超划算,手慢則無!',
timeStart: 0,
timeEnd: 0,
isCanToAlbum: false, // 是否授權儲存圖片到相簿
showModal: false // 是否展示彈窗
};
}
// onLoad
async componentWillMount() {
Taro.showLoading({
title: '海報生成中...',
mask: true,
})
const {token} = this.props.authData;
await this.getUserInfoFn(token);
}
// onReady
componentDidMount() { }
// onShow
componentDidShow() { }
// onHide
componentDidHide() { }
// onUnload
componentWillUnmount() { }
// 獲取頭像和姓名以及二維碼等資訊
async getUserInfoFn(data) {
const resp = await getUserInfoApi(data);
const {Collageid} =this.props.payInfoData.data;
let path = `pages/payCollage/payCollage?collageId=${Collageid}`
const codeResp = await getLittleAppQRCodeApi(path);
const codeImg = codeResp.data;
const {headPhoto, studentName} = resp.data;
this.setState({
headPhoto,
studentName,
codeImg
});
const BGIMG = await this.downloadHttpImg(this.state.bgImg);
const headPhotoImg = await this.downloadHttpImg(headPhoto);
const codeImgSrc = await this.downloadHttpImg(codeImg);
this.setState({
bgSrc: BGIMG,
avatorSrc: headPhotoImg,
codeSrc: codeImgSrc
}, () => {
this.sharePosteCanvas()
})
}
// 封裝的下載圖片函式
// httpImg: string 圖片地址 要是https的哦!
downloadHttpImg (httpImg) {
return new Promise(((resolve, reject) => {
Taro.downloadFile({
url: httpImg,
success: (res) => {
if (res.statusCode === 200) {
resolve(res.tempFilePath)
} else {
Taro.showToast({
title: '圖片下載失敗!',
icon:'none',
duration: 2000
})
}
},
fail: (res) => {
Taro.showModal({
title: '提示圖片下載失敗!',
content: `原因:${JSON.stringify(res)}`,
success(res) {
if (res.confirm) {
console.log('使用者點選確定')
} else if (res.cancel) {
console.log('使用者點選取消')
}
}
})
}
})
}))
}
// 畫圖
sharePosteCanvas () {
let studentName = this.state.studentName;
let avaterSrc = this.state.avatorSrc;
let codeSrc = this.state.codeSrc;
let bgImg = this.state.bgSrc;
const ctx = Taro.createCanvasContext('posterCanvas');
Taro.createSelectorQuery().select('#collagePosterId').boundingClientRect((rect) => {
let height = rect.height,
width = rect.width,
studentNameTop = height * 0.27,
avatorWidth = width * 0.17, // 頭像大小
avatorTop = height * 0.1394,
avatorleft = (width - avatorWidth) / 2,
codeWidth = width * 0.2, // 二維碼大小
codeHeight = width * 0.2 * 1.16, // 二維碼大小
codeTop = height * 0.76,
codeLeft = width * 0.67,
circle = {
x : avatorleft + avatorWidth / 2,
y : avatorTop + avatorWidth / 2,
r : avatorWidth / 2
},
textLeft = width / 2;
ctx.setFillStyle('#fff');
ctx.fillRect(0, 0, width, height);
// 背景
if (bgImg) {
ctx.drawImage(bgImg, 0, 0, rect.width, height);
}
// 頭像
if (avaterSrc) {
ctx.save();
ctx.beginPath();
ctx.arc(circle.x, circle.y, circle.r, 0, Math.PI * 2, false);
ctx.setFillStyle('#EEEEEE')
ctx.fill()
ctx.clip(); //剪下路徑
ctx.drawImage(avaterSrc, avatorleft, avatorTop, avatorWidth, avatorWidth);
ctx.restore();
}
// 使用者資訊 - 姓名
if (studentName) {
ctx.setFontSize(16);
ctx.setFillStyle('#fff');
ctx.setTextAlign('center');
ctx.fillText(studentName, textLeft, studentNameTop, 300);
}
// 繪製二維碼
if (codeSrc) {
ctx.drawImage(codeSrc, codeLeft , codeTop, codeWidth, codeHeight)
}
}).exec()
setTimeout(() => {
ctx.draw(); // 這裡有個需要注意就是,這個方法是在繪製完成之後在呼叫,不然容易其它被覆蓋。
wx.hideLoading();
}, 1000)
setTimeout(() => {
this.handleSaveImg()
}, 1000)
}
handleTimeStart () {
this.setState({
timeStart: new Date().getTime()
})
}
// 儲存圖片
handleSaveImg () {
let that = this;
Taro.getSetting({
success: (res) => {
Taro.authorize({
scope: 'scope.writePhotosAlbum',
success: (res) => {
this.downloadImgToAlbum()
},
fail: (res) => {
// 授權失敗 不能儲存圖片
that.setState({
showModal: true,
isCanToAlbum: false
})
}
})
}
})
}
// 儲存圖片到相簿
downloadImgToAlbum () {
let that = this;
Taro.canvasToTempFilePath({
canvasId: 'posterCanvas',
success: (res) => {
let imgUrl = res.tempFilePath;
Taro.saveImageToPhotosAlbum({
filePath: imgUrl,
success (res) {
that.setState({
showModal: true,
isCanToAlbum: true
})
},
fail (res) {
that.setState({
showModal: true,
isCanToAlbum: false
})
}
})
}
});
}
// 關閉彈窗
handleCloseModal () {
this.setState({
showModal: false
})
}
// 複製文字
copyText () {
Taro.setClipboardData({data: this.state.shareText}).then(() => {
Taro.showToast({
title: '複製成功'
})
})
}
render() {
const {
headPhoto,
studentName,
showModal,
isCanToAlbum,
bgImg,
codeImg,
shareText
} = this.state;
return (
<View>
<View
className='collagePoster'
ref='collagePoster'
id='collagePosterId'
// onTouchStart={this.handleTimeStart}
onLongPress={this.handleSaveImg}
>
<View className='main'>
<View className='userInfoWrapper'>
{headPhoto && <Image src={headPhoto} alt='頭像' className='avator'></Image>}
<Text>{studentName}</Text>
</View>
{codeImg && <Image src={codeImg} alt='二維碼' className='codeImg'></Image>}
<Image src={bgImg} alt='背景圖' className='bg_img'></Image>
</View>
<View className='space'></View>
<canvas canvas-id="posterCanvas" style="width:750rpx;height:1334rpx;" />
</View>
{
showModal ?
<View className='model-poster'>
<View className='model-body'>
<View className="modal-btn-close" onClick={this.handleCloseModal}></View>
<View className='model-title'>{isCanToAlbum ? '- 海報已儲存至相簿 -' : '- 海報已生成,請截圖儲存 -'}</View>
<View className='model-tip'>複製文字一起分享,成功率翻3倍</View>
<View className='model-content'>{shareText}</View>
<Button onClick={this.copyText}>一鍵複製文字</Button>
</View>
</View> : null
}
</View>
);
}
}
複製程式碼
坑
- 由介面拿到的圖片地址是https的要經過wx.downloadFile轉換一下。若不轉換則在實際的手機上繪製的圖是空白的無法正常實現繪製。
- 需要配置小程式域名資訊中的downloadFile 合法域名。若不配置則在部分手機上開啟除錯工具的時候能正常執行,不開啟除錯工具的話不能正常繪圖。