React中实现截图功能并导出图片

442 阅读1分钟

需求

最近在处理业务上遇到一个问题,需要将一个图片+文字组合合成为一张图并导出给用户,类似于截图功能

思考

处理合成图片这一步,首先我们想到的可能是canvas的toDataURL会更多,将canvas和文字画在canvas中再导出成图片,下面介绍另外一种方法,就是利用svg的foreignObject标签进行xml解析,这样就能在svg中嵌入dom元素进行合成。这样也能实现合成效果,在canIuse上查询兼容性也是大多数支持,只是移动端的某些浏览器暂不支持,pc可以放心使用

由于我们的功能是在移动端上实现的,所以目前还是选择了canvas方法,这里再介绍下html2canvas库,由于我们的文字数据里存在富文本数据,所以无法直接用canvas的原生方式,需要额外的库帮我们处理dom Tree,使用html2canvas将dom直接画进canvas处理,如果数据中只存在文本数据,还是推荐使用原生的fillText进行绘制,毕竟需要考虑安装格外的npm包所带来的权衡

需要注意的是,要在img Dom渲染完成再进行截图操作,这里推荐在img的onLoad Event里进行截图操作,这里附带一个完整的demo


const Index = () => {
    const { data } = useFetch(getDonateInfo)
    const pictureWrapper = useRef(null)
    const ImgCache = useRef()

    const handleImgCache = () => html2Canvas(pictureWrapper.current).then(canvas => {
        const dataURL = canvas.toDataURL('image/png')
        ImgCache.current = dataURL
    })

    const handleShowImg = () => ImgCache.current && Modal.show({
        image: ImgCache.current,
        closeOnMaskClick: true,
    })

    return (
        <div className={style.wrapper}>
            <div className={style.top}>
                捐赠成功!
            </div>
            <div className={style.content} onClick={handleShowImg} ref={pictureWrapper}>
                <Img id={data?.jzzsdt} onLoad={handleImgCache} />
                <div dangerouslySetInnerHTML={{ __html: data?.jzzswa }}></div>
            </div>
        </div>
    );
};

export default Index;