549 lines
16 KiB
Vue
549 lines
16 KiB
Vue
<template>
|
|
<view>
|
|
<fu-popup v-model="sharePopup" mode="bottom" :safe-area-inset-bottom="true" :mask-close-able="true" border-radius="24">
|
|
<view class="wrap">
|
|
<view class="flex">
|
|
<view class="flex-sub text-center">{{ $t('分享到') }}</view>
|
|
<view class="cuIcon-close" @tap.stop="close"></view>
|
|
</view>
|
|
<view class="padding-tb">
|
|
<!-- APP平台 start -->
|
|
<!-- #ifdef APP-PLUS -->
|
|
<view class="grid col-4">
|
|
<block v-for="(item, index) in shareList" :key="index">
|
|
<view v-if="provider.includes(item.type)" class="height-200 flex flex-direction align-center justify-center" @tap.stop="share(item)">
|
|
<image class="block-85" :src="item.icon" mode="aspectFit"></image>
|
|
<text class="margin-top-xs text-sm">{{ item.title }}</text>
|
|
</view>
|
|
</block>
|
|
</view>
|
|
<!-- #endif -->
|
|
<!-- APP平台 end -->
|
|
|
|
<!-- 微信小程序平台 start -->
|
|
<!-- #ifdef MP-WEIXIN -->
|
|
<view class="grid col-2">
|
|
<view>
|
|
<button class="height-200 flex flex-direction align-center justify-center cu-btn bg-white" open-type="share">
|
|
<image class="block-85" :src="require('./static/weixin.png')" mode="aspectFit"></image>
|
|
<text class="margin-top-xs text-sm">{{ $t('微信好友') }}</text>
|
|
</button>
|
|
</view>
|
|
<view>
|
|
<button class="height-200 flex flex-direction align-center justify-center cu-btn bg-white" @tap.stop="createPoster">
|
|
<image class="block-85" :src="require('./static/poster.png')" mode="aspectFit"></image>
|
|
<text class="margin-top-xs text-sm">{{ $t('二维码海报') }}</text>
|
|
</button>
|
|
</view>
|
|
</view>
|
|
<!-- #endif -->
|
|
<!-- 微信小程序平台 end -->
|
|
|
|
<!-- H5平台 staart -->
|
|
<!-- #ifdef H5 -->
|
|
<view class="grid col-3">
|
|
<view>
|
|
<button class="height-200 flex flex-direction align-center justify-center cu-btn bg-white" @tap.stop="createPoster">
|
|
<image class="block-85" :src="require('./static/poster.png')" mode="aspectFit"></image>
|
|
<text class="margin-top-xs text-sm">{{ $t('二维码海报') }}</text>
|
|
</button>
|
|
</view>
|
|
</view>
|
|
<!-- #endif -->
|
|
<!-- H5平台 end -->
|
|
</view>
|
|
</view>
|
|
</fu-popup>
|
|
<fu-popup v-model="posterPopup" mode="bottom" :safe-area-inset-bottom="true" :mask-close-able="true" border-radius="24">
|
|
<view class="wrap">
|
|
<view class="flex align-center justify-between">
|
|
<view class="text-df text-333">{{ $t('保存到相册') }}</view>
|
|
<view class="cuIcon-close text-333" @click.stop="close"></view>
|
|
</view>
|
|
<view class="margin-top flex justify-center align-center">
|
|
<image class="preview-image" :src="previewImageUrl" mode="aspectFill" @click="previewImage(previewImageUrl)"></image>
|
|
</view>
|
|
<!-- #ifndef H5 -->
|
|
<view class="margin-top" @click="saveImage">
|
|
<button class="action2 cu-btn block round">{{ $t('保存图片') }}</button>
|
|
</view>
|
|
<!-- #endif -->
|
|
</view>
|
|
</fu-popup>
|
|
<view class="offset-canvas">
|
|
<canvas canvas-id="poster-canvas" style="width: 375px; height: 550px"></canvas>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
/**
|
|
* @alias 刘欢
|
|
* @description 常规分享组件,提供分享到微信,微信朋友圈,QQ,QQ空间,分享海报等功能
|
|
* @param { Boollean } isShareToMp 是否分享到小程序
|
|
* */
|
|
const providers = [
|
|
{
|
|
title: global.i18n.t('微信好友'),
|
|
icon: require('./static/weixin.png'),
|
|
type: 'weixin',
|
|
scene: 'WXSceneSession',
|
|
},
|
|
{
|
|
title: global.i18n.t('朋友圈'),
|
|
icon: require('./static/pengyouquan.png'),
|
|
type: 'weixin',
|
|
scene: 'WXSenceTimeline',
|
|
},
|
|
{
|
|
title: global.i18n.t('QQ好友'),
|
|
icon: require('./static/qq.png'),
|
|
type: 'qq',
|
|
},
|
|
{
|
|
title: global.i18n.t('QQ空间'),
|
|
icon: require('./static/kongjian.png'),
|
|
type: 'qq',
|
|
},
|
|
{
|
|
title: global.i18n.t('新浪微博'),
|
|
icon: require('./static/weibo.png'),
|
|
type: 'sinaweibo',
|
|
},
|
|
{
|
|
title: global.i18n.t('复制链接'),
|
|
icon: require('./static/copy.png'),
|
|
type: 'link',
|
|
},
|
|
{
|
|
title: global.i18n.t('二维码海报'),
|
|
icon: require('./static/poster.png'),
|
|
type: 'image',
|
|
},
|
|
]
|
|
export default {
|
|
props: {
|
|
info: Object,
|
|
isShareToMp: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
},
|
|
data() {
|
|
return {
|
|
ctx: null,
|
|
previewImageUrl: '',
|
|
shareList: [
|
|
{
|
|
title: global.i18n.t('微信好友'),
|
|
icon: require('./static/weixin.png'),
|
|
type: 'weixin',
|
|
scene: 'WXSceneSession',
|
|
},
|
|
{
|
|
title: global.i18n.t('朋友圈'),
|
|
icon: require('./static/pengyouquan.png'),
|
|
type: 'weixin',
|
|
scene: 'WXSenceTimeline',
|
|
},
|
|
{
|
|
title: global.i18n.t('QQ好友'),
|
|
icon: require('./static/qq.png'),
|
|
type: 'qq',
|
|
},
|
|
{
|
|
title: global.i18n.t('QQ空间'),
|
|
icon: require('./static/kongjian.png'),
|
|
type: 'qq',
|
|
},
|
|
{
|
|
title: global.i18n.t('新浪微博'),
|
|
icon: require('./static/weibo.png'),
|
|
type: 'sinaweibo',
|
|
},
|
|
{
|
|
title: global.i18n.t('复制链接'),
|
|
icon: require('./static/copy.png'),
|
|
type: 'link',
|
|
},
|
|
{
|
|
title: global.i18n.t('二维码海报'),
|
|
icon: require('./static/poster.png'),
|
|
type: 'image',
|
|
},
|
|
],
|
|
provider: [], // 已配置的服务供应商
|
|
sharePopup: false,
|
|
posterPopup: false,
|
|
}
|
|
},
|
|
methods: {
|
|
// 图片点击放大
|
|
previewImage(url) {
|
|
uni.previewImage({
|
|
current: url,
|
|
urls: [url],
|
|
})
|
|
},
|
|
// 打开弹窗
|
|
open() {
|
|
console.log(this.info, 888888)
|
|
this.sharePopup = true
|
|
},
|
|
// 关闭弹窗
|
|
close() {
|
|
this.sharePopup = false
|
|
this.posterPopup = false
|
|
},
|
|
// 初始化分享数据
|
|
init() {
|
|
this.sharePopup = false
|
|
this.posterPopup = true
|
|
this.initCanvas()
|
|
console.log('init????')
|
|
},
|
|
// 获取服务商列表
|
|
getProvider() {
|
|
uni.getProvider({
|
|
service: 'share',
|
|
success: (data) => {
|
|
console.log('已配置的分享服务', data)
|
|
this.provider = [...data.provider, 'link', 'image']
|
|
},
|
|
})
|
|
},
|
|
// 分享
|
|
share(item) {
|
|
let _scene = ''
|
|
let _provider = item.type
|
|
let _type = 0
|
|
switch (_provider) {
|
|
case 'weixin':
|
|
_scene = item.scene
|
|
uni.share({
|
|
provider: _provider,
|
|
type: _type,
|
|
title: this.info.goodsName,
|
|
scene: _scene,
|
|
summary: this.info.summary,
|
|
href: this.info.href,
|
|
imageUrl: this.info.goodsImage,
|
|
success: (res) => {
|
|
this.close()
|
|
},
|
|
fail: (err) => {
|
|
console.log('分享失败', err)
|
|
this.$message.info(global.i18n.t('分享失败'))
|
|
},
|
|
})
|
|
break
|
|
case 'qq':
|
|
_type = 1
|
|
uni.share({
|
|
provider: _provider,
|
|
type: _type,
|
|
title: this.info.goodsName,
|
|
scene: _scene,
|
|
summary: this.info.summary,
|
|
href: this.info.href,
|
|
imageUrl: this.info.goodsImage,
|
|
success: (res) => {
|
|
this.close()
|
|
},
|
|
fail: (err) => {
|
|
console.log('分享失败', err)
|
|
this.$message.info(global.i18n.t('分享失败'))
|
|
},
|
|
})
|
|
break
|
|
case 'sinaweibo':
|
|
uni.share({
|
|
provider: _provider,
|
|
type: _type,
|
|
title: this.info.goodsName,
|
|
scene: _scene,
|
|
summary: this.info.summary,
|
|
href: this.info.href,
|
|
imageUrl: this.info.goodsImage,
|
|
success: (res) => {
|
|
this.close()
|
|
},
|
|
fail: (err) => {
|
|
console.log('分享失败', err)
|
|
this.$message.info(global.i18n.t('分享失败'))
|
|
},
|
|
})
|
|
break
|
|
case 'link':
|
|
uni.setClipboardData({
|
|
data: this.info.href,
|
|
success: () => {
|
|
this.$message.success(global.i18n.t('复制成功'))
|
|
this.close()
|
|
},
|
|
})
|
|
break
|
|
case 'image':
|
|
this.createPoster()
|
|
break
|
|
}
|
|
},
|
|
// 生成海报
|
|
createPoster() {
|
|
console.log('生成海报')
|
|
this.$util.actionAuth(() => {
|
|
this.$emit('getPosterInfo')
|
|
})
|
|
},
|
|
// 初始化画布
|
|
initCanvas() {
|
|
uni.showLoading({
|
|
title: global.i18n.t('海报生成中...'),
|
|
mask: true,
|
|
})
|
|
console.log('开始绘图', this.info)
|
|
this.ctx = uni.createCanvasContext('poster-canvas', this)
|
|
setTimeout(() => {
|
|
this.drawBack()
|
|
}, 200)
|
|
},
|
|
// 绘制背景
|
|
drawBack() {
|
|
let ctx = this.ctx
|
|
ctx.setFillStyle('#FFFFFF')
|
|
ctx.fillRect(0, 0, 375, 550)
|
|
ctx.draw(false, () => {
|
|
console.log('背景绘制成功')
|
|
this.drawUserInfo()
|
|
})
|
|
},
|
|
// 绘制个人信息
|
|
async drawUserInfo() {
|
|
let ctx = this.ctx
|
|
console.log(this.info)
|
|
await new Promise((resolve) => {
|
|
uni.getImageInfo({
|
|
src: this.info.avatar,
|
|
success: (res) => {
|
|
console.log('头像图片', res)
|
|
let { width, height, path } = res
|
|
if (width > height) {
|
|
let startX = (width - height) / 2
|
|
ctx.drawImage(res.path, startX, 0, height, height, 20, 20, 50, 50)
|
|
} else if (width < height) {
|
|
let startY = (height - width) / 2
|
|
ctx.drawImage(res.path, 0, startY, width, width, 20, 20, 50, 50)
|
|
} else {
|
|
ctx.drawImage(res.path, 20, 20, 50, 50)
|
|
}
|
|
resolve()
|
|
},
|
|
fail: (err) => {
|
|
uni.hideLoading()
|
|
this.$message.info(global.i18n.t('获取头像信息失败'))
|
|
console.log('获取图片信息失败', err)
|
|
},
|
|
})
|
|
})
|
|
|
|
ctx.setFillStyle('#333333')
|
|
ctx.setFontSize(18)
|
|
ctx.fillText(this.info.name, 90, 40)
|
|
ctx.setFillStyle('#999999')
|
|
ctx.setFontSize(16)
|
|
ctx.fillText(global.i18n.t('推荐一个好物给你,请查收'), 90, 65)
|
|
ctx.draw(true, () => {
|
|
console.log('个人信息绘制成功')
|
|
this.drawGoodsImage()
|
|
})
|
|
},
|
|
// 绘制商品图片
|
|
async drawGoodsImage() {
|
|
let ctx = this.ctx
|
|
await new Promise((resolve) => {
|
|
uni.getImageInfo({
|
|
src: this.info.goodsImage,
|
|
success: (res) => {
|
|
console.log('商品图片', res)
|
|
let { width, height, path } = res
|
|
if (width > height) {
|
|
let startX = (width - height) / 2
|
|
ctx.drawImage(res.path, startX, 0, height, height, 20, 90, 335, 335)
|
|
} else if (width < height) {
|
|
let startY = (height - width) / 2
|
|
ctx.drawImage(res.path, 0, startY, width, width, 20, 90, 335, 335)
|
|
} else {
|
|
ctx.drawImage(res.path, 20, 90, 335, 335)
|
|
}
|
|
resolve()
|
|
},
|
|
fail: (err) => {
|
|
uni.hideLoading()
|
|
console.log('商品图片绘制失败', err)
|
|
this.$message.info(global.i18n.t('获取商品图片信息失败'))
|
|
},
|
|
})
|
|
})
|
|
ctx.draw(true, () => {
|
|
console.log('商品图片绘制成功')
|
|
this.drawGoodsInfo()
|
|
})
|
|
},
|
|
// 绘制商品名称价格
|
|
drawGoodsInfo() {
|
|
let ctx = this.ctx
|
|
this.drawText(ctx, this.info.goodsName, 20, 455, 240, 2, '#333333', 18)
|
|
ctx.setFontSize(20)
|
|
ctx.setFillStyle('#d55034')
|
|
ctx.fillText('¥' + this.info.price, 20, 510)
|
|
ctx.draw(true, () => {
|
|
console.log('商品信息绘制成功')
|
|
this.drawCode()
|
|
// this.exportImage();
|
|
})
|
|
},
|
|
// 绘制二维码
|
|
async drawCode() {
|
|
let ctx = this.ctx
|
|
await new Promise((resolve) => {
|
|
uni.getImageInfo({
|
|
src: this.info.code,
|
|
success: (res) => {
|
|
console.log('二维码信息', res)
|
|
let { width, height, path } = res
|
|
if (width > height) {
|
|
let startX = (width - height) / 2
|
|
ctx.drawImage(res.path, startX, 0, height, height, 275, 445, 80, 80)
|
|
} else if (width < height) {
|
|
let startY = (height - width) / 2
|
|
ctx.drawImage(res.path, 0, startY, width, width, 275, 445, 80, 80)
|
|
} else {
|
|
ctx.drawImage(res.path, 275, 445, 80, 80)
|
|
}
|
|
resolve()
|
|
},
|
|
fail: (err) => {
|
|
console.log('二维码绘制失败', err)
|
|
uni.hideLoading()
|
|
this.$message.info(global.i18n.t('获取二维码信息失败'))
|
|
},
|
|
})
|
|
})
|
|
ctx.draw(true, () => {
|
|
console.log('二维码绘制成功')
|
|
this.exportImage()
|
|
})
|
|
},
|
|
// 导出图片
|
|
exportImage() {
|
|
uni.canvasToTempFilePath(
|
|
{
|
|
canvasId: 'poster-canvas',
|
|
success: (res) => {
|
|
uni.hideLoading()
|
|
console.log('导出图片成功', res)
|
|
this.previewImageUrl = res.tempFilePath
|
|
},
|
|
fail: (err) => {
|
|
uni.hideLoading()
|
|
console.log('导出图片失败', err)
|
|
},
|
|
},
|
|
this
|
|
)
|
|
},
|
|
// 保存图片
|
|
saveImage() {
|
|
uni.saveImageToPhotosAlbum({
|
|
filePath: this.previewImageUrl,
|
|
success: (res) => {
|
|
console.log(res)
|
|
this.$message.info(global.i18n.t('保存成功'))
|
|
this.close()
|
|
},
|
|
})
|
|
},
|
|
/**
|
|
* @description 绘制图片通用方法
|
|
* @param {Object} ctx - canvas上下文
|
|
* @param {String} 图片路径 - canvas上下文
|
|
* */
|
|
async drawImage(ctx, path) {},
|
|
/**
|
|
* @description 绘制文本通用方法
|
|
* @param {Object} ctx - canvas上下文
|
|
* @param {String} text - 文本
|
|
* @param {Number} startX - X轴开始位置
|
|
* @param {Number} startY - Y轴开始位置
|
|
* @param {Number} limitWidth - 文字绘制区限制宽度
|
|
* @param {Number} limitLine - 文字绘制限制行数
|
|
* @param {String} color - 文字颜色
|
|
* @param {Number} size - 字体大小
|
|
* */
|
|
drawText(ctx, text, startX, startY, limitWidth, limitLine = 2, color = '#333333', size = 18, isBold = false) {
|
|
ctx.setFillStyle(color)
|
|
ctx.setFontSize(size)
|
|
let arrText = text.split('')
|
|
let line = ''
|
|
let column = 0
|
|
for (let n = 0, len = arrText.length; n < len; n++) {
|
|
let testline = line + arrText[n]
|
|
let metrics = ctx.measureText(testline)
|
|
let testWidth = metrics.width
|
|
if (testWidth > limitWidth && n > 0 && column < limitLine) {
|
|
ctx.fillText(line, startX, startY)
|
|
column += 1
|
|
line = arrText[n]
|
|
startY += size * 1.5
|
|
} else {
|
|
line = testline
|
|
}
|
|
}
|
|
if (column < limitLine) {
|
|
ctx.fillText(line, startX, startY)
|
|
}
|
|
},
|
|
},
|
|
created() {
|
|
console.log('组件 created')
|
|
this.getProvider()
|
|
},
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.wrap {
|
|
padding: 30rpx;
|
|
}
|
|
|
|
.block-85 {
|
|
width: 85rpx;
|
|
height: 85rpx;
|
|
}
|
|
|
|
.height-200 {
|
|
height: 200rpx;
|
|
}
|
|
|
|
.action2 {
|
|
height: 80rpx;
|
|
background-color: #f02523;
|
|
font-size: 32rpx;
|
|
color: #ffffff;
|
|
}
|
|
|
|
.preview-image {
|
|
width: 375rpx;
|
|
height: 550rpx;
|
|
border-radius: 8rpx;
|
|
box-shadow: 0 0 10rpx rgba(0, 0, 0, 0.2);
|
|
}
|
|
|
|
.offset-canvas {
|
|
position: fixed;
|
|
top: -1000px;
|
|
left: 0;
|
|
z-index: 9999;
|
|
}
|
|
</style>
|