小程序使用taro将两张图合在一起,并保存到相册
作者:互联网
// index.tsx
import React, { useState, useEffect, useCallback, FC } from 'react'
import {
useShareAppMessage,
getImageInfo,
createCanvasContext,
canvasToTempFilePath,
getStorageSync,
showToast,
showModal,
hideLoading,
showLoading,
} from '@tarojs/taro'
import { AtActionSheet } from 'taro-ui'
import { View, Image, Button, Canvas } from '@tarojs/components'
import MainLayout from '@/layout/MainLayout'
import LoginButton from '@/components/LoginButton'
import ShareImageModal from './ShareImageModal'
import { fetchQRCode } from '@/apis/detail'
import shareImage from './share-image-icon.png'
import shareWx from './share-wx-icon.png'
import sharePaper from './sharePaper.png'
import activeDetail from './activeDetail@3x.png'
import './index.scss'
const Spread: FC = () => {
// const userInfo = useUserInfo<IRecommenderUserInfo>()
const [isOpen, setIsOpen] = useState(false)
const [shareImageModal, setShareImageModal] = useState(false)
const [isLoading, setIsLoading] = useState(false)
const [qrCodeUrl, setQrCodeUrl] = useState<string>('')
const [tpmPath, setTpmPath] = useState('')
const [loadFlag, setLoadFlag] = useState(false)
const [imgHeight, setImgHeight] = useState<number>(1)
const isAccredit = getStorageSync('accredit') || false
const onShareClick = val => {
if (val) {
// setIsOpen(true)
setShareImageModal(true)
} else {
showToast({ title: '请授权手机号!', icon: 'none' })
}
}
useShareAppMessage(() => ({
title: '1234',
path: ``,
imageUrl: '',
}))
const onShareWX = () => {
setTimeout(() => setIsOpen(false), 250)
}
const onShareImg = () => {
setShareImageModal(true)
setTimeout(() => setIsOpen(false), 250)
}
useEffect(() => {
setIsLoading(true)
fetchQRCode()
.then(res => setQrCodeUrl(res.qrCodeUrl))
.finally(() => setIsLoading(false))
}, [])
const imgToCanvas = useCallback(async () => {
if (qrCodeUrl) {
const canvas = createCanvasContext('canvasId')
// showLoading({
// title: '正在保存',
// mask: true
// })
getImageInfo({
src: sharePaper,
}).then((res: any) => {
canvas.drawImage(sharePaper, 0, 0, res.width / 3, res.height / 3)
getImageInfo({
src: qrCodeUrl,
})
.then(qrRes => {
canvas.drawImage(
qrRes.path, // 将网络图片路径转成本地路径,因为drawImage的第一个参数是图片的本地路径;(所要绘制的图片资源(网络图片要通过 getImageInfo / downloadFile 先下载))
30,
res.height / 3 - 115,
qrRes.width / 5,
qrRes.height / 5
)
canvas.draw(true, () => {
canvasToTempFilePath({
canvasId: 'canvasId',
fileType: 'png',
}).then(res => setTpmPath(res.tempFilePath))
})
})
.catch(res => {
// hideLoading()
showModal({
title: '温馨提示',
content: '小程序码图片合成失败,请重试',
showCancel: false,
})
})
})
}
}, [qrCodeUrl])
useEffect(() => {
imgToCanvas()
}, [imgToCanvas])
const onl oadImg = res => {
setLoadFlag(true)
setImgHeight(res.detail.height / 2)
}
const renderMenu = () => {
return (
<AtActionSheet isOpened={isOpen} cancelText="取消" onCancel={() => setIsOpen(false)}>
<Button hoverClass="hover" onClick={onShareWX} openType="share">
<Image src={shareWx} className="img" />
<View className="txt">分享微信</View>
</Button>
<View onClick={onShareImg}>
<Image src={shareImage} className="img" />
<View className="txt">分享图片</View>
</View>
</AtActionSheet>
)
}
return (
<MainLayout className="spread">
<View>
<Image
className="wp100"
style={{ height: loadFlag ? imgHeight : 1 }}
src={activeDetail}
onl oad={onLoadImg}
// mode="widthFix"
/>
{/* <Image className="wp100" src={activeDetail} mode="widthFix" /> */}
{/* {renderMenu()} */}
<Canvas canvasId="canvasId" className="canvas"></Canvas>
<View className="botm">
{isAccredit ? (
<Button className="btn" onClick={onShareClick}>
分享返利
</Button>
) : (
<LoginButton className="btn" onLoginSuccess={onShareClick}>
分享返利
</LoginButton>
)}
</View>
<ShareImageModal
isOpen={shareImageModal}
onClose={() => setShareImageModal(false)}
tpmPath={tpmPath}
/>
</View>
</MainLayout>
)
}
export default Spread
其中canvas的样式,为了不在当当前页面展示
.canvas{
width: 375PX;
height: 812PX;
visibility: hidden;
position: fixed;
top: 99999px;
left: 99999px;
}
// ShareImageModal.tsx
import React, { useEffect, useState } from 'react'
import c from 'classnames'
import { noop } from 'lodash'
import {
showLoading,
hideLoading,
showToast,
authorize,
saveImageToPhotosAlbum,
// getFileSystemManager
} from '@tarojs/taro'
import { View, Image, Swiper, SwiperItem } from '@tarojs/components'
import { useDebounce } from 'ahooks'
import './shareimage.scss'
export interface IShareImageModalProps extends IProps, IModalProps {
title?: string
onClose?(): void
sharePath?: string
tpmPath: string
}
const ShareImageModal: React.FC<IShareImageModalProps> = props => {
const { isOpen, onClose = noop, sharePath = '', tpmPath} = props
const debouncedOpen = useDebounce(isOpen, { wait: 250 })
const delayOpen = useDebounce(isOpen, { wait: 10 }) && isOpen
const [current, setCurrent] = useState(1)
const [images, setImages] = useState<Array<{ fileUrl: string; enabled: boolean; id: number }>>([])
useEffect(() => {
if (isOpen) {
Promise.resolve([{fileUrl: tpmPath, enabled:false, id:1 }])
.then(res => {
setImages(res)
setCurrent(Math.max(0, Math.floor((res.length - 1) / 2)))
})
}
}, [sharePath, isOpen, images.length])
// 点击保存图片
const saveImageClickHandler = () => {
showLoading({ title: '生成分享图...', mask: true })
authorize({ scope: 'scope.writePhotosAlbum' })
.then(() => {
saveImageToPhotosAlbum({
filePath: tpmPath,
success (res: TaroGeneral.CallbackResult) {
showToast({ title: '分享图已成功保存到相册', icon: 'none' })
},
fail (res: TaroGeneral.CallbackResult) {
showToast({ title: '生成分享图失败,请重试', icon: 'none' })
},
complete (res: TaroGeneral.CallbackResult) {
hideLoading()
}
})
})
.catch(() => void showToast({ title: '请授权保存图片权限以保存分享图', icon: 'none' }))
}
// 图片选择器切换
const swiperChangeHandler = e => {
const newIndex = e.detail.current
setCurrent(newIndex)
}
// 此时弹窗处于关闭状态
if (!isOpen && !debouncedOpen) {
return null
}
return (
<View className="share-image-modal" catchMove>
<View
className={c('share-image-modal__body', {
'share-image-modal__body--actived': delayOpen,
})}
>
<View className="menu-content">
<Swiper
current={current}
onChange={swiperChangeHandler}
previousMargin="140rpx"
nextMargin="140rpx"
duration={200}
className="swiper"
>
{images.map((item, index) => (
<SwiperItem
onClick={() => void setCurrent(index)}
className="swiper__item"
key={item.id}
>
<Image
className={c('swiper__image', { current: index === current })}
src={item.fileUrl}
mode="aspectFit"
/>
</SwiperItem>
))}
</Swiper>
</View>
<View onClick={onClose} className="close at-icon at-icon-close"></View>
<View onClick={saveImageClickHandler} className="confirm">
保存图片
</View>
</View>
<View
className={c('share-image-modal__mask', {
'share-image-modal__mask--actived': delayOpen,
})}
></View>
</View>
)
}
export default ShareImageModal
// shareimage.scss
.share-image-modal {
z-index: 5;
&__mask {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: rgba(0, 0, 0, 0.6);
transition: opacity 250ms;
opacity: 0;
&--actived {
opacity: 1;
}
}
&__body {
z-index: 8;
position: fixed;
width: 100%;
overflow: hidden;
transition: all 250ms;
bottom: calc(-1100px - #{$pageBottom});
&--actived {
bottom: 0;
}
.menu-content {
background: #F5F6FA;
border-radius: 24px 24px 0px 0px;
height: 1000px;
padding: 70px 0 60px;
}
.swiper-skeleton {
height: 866px;
width: 100%;
background: transparent;
}
.swiper {
height: 866px;
width: 100%;
&__item {
width: 400px;
height: 866px;
display: flex;
align-items: center;
justify-content: center;
}
&__image {
width: 360px;
height: 780px;
box-shadow: 0px 4px 28px 0px rgba(0, 0, 0, 0.15);
border-radius: 16px;
transition: all 200ms;
&.current {
width: 400px;
height: 866px;
}
}
}
.confirm {
background: #FFFFFF;
bottom: 0;
height: calc(100px + #{$pageBottom});
padding-bottom: $pageBottom;
line-height: 80px;
text-align: center;
font-size: 32px;
font-weight: 500;
color: #0F1E3E;
line-height: 100px;
}
.close {
position: absolute;
top: 28px;
right: 28px;
font-size: 30px;
color: #C2C2C2;
&::after {
content: ' ';
z-index: 15;
position: absolute;
top: -30px;
bottom: -30px;
right: -30px;
left: -30px;
}
}
}
}
标签:合在一起,const,相册,res,height,useState,import,taro,false 来源: https://www.cnblogs.com/wangwenhui/p/16071095.html