需求
最近在处理业务上遇到一个问题,需要将一个图片+文字组合合成为一张图并导出给用户,类似于截图功能
思考
处理合成图片这一步,首先我们想到的可能是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;