记录--组件阅后即焚?挂载即卸载!看完你就理解了

这篇具有很好参考价值的文章主要介绍了记录--组件阅后即焚?挂载即卸载!看完你就理解了。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助

记录--组件阅后即焚?挂载即卸载!看完你就理解了

前言

上家公司有个需求是批量导出学生的二维码,我一想这简单啊,不就是先批量获取学生数据,然后根据QRcode生成二维码,然后在用html2canvas导出成图片嘛。 由于公司工具库有现成的生成压缩包方法,我只需要获得对应的图片blob就可以了,非常的easy啊。

开始动手

思路没啥问题,但第一步就犯了难,用过react框架或者其他MVVM框架的都知道,这种类型的框架都是数据驱动视图,也就是说一般情况下,必须先获得数据,然后根据数据才能得到视图。

但是问题是,html2canvas也是必须需要获取真实dom的快照然后转换成canvas对象。

听着好像不冲突,诶,我先获取数据,然后渲染出视图,在依次通过html2canvas来生成图片不就完事了嘛!但是想归想,却不能这么做。

原因主要有两个,一个原因呢是交互逻辑上就行不太通,也不友好。你不能“啪”点一下导出按钮,然后获取数据之后再去等所有数据渲染出对应组件之后,再去延迟处理导出逻辑。(耗时太长)

另一个原因呢,主要是跟html2canvas这个工具库有关系了,它的原理简单来说呢,就是复制你期望获取截图的那个dom的渲染树,然后根据这个渲染树在当前页面生成一个你看不见的canvas dom对象来。那么问题来了,因为是批量下载,所以肯定会有大量的数据,那么如果不做处理,就会有大量的canvas对象存在当前页面。

canvas标签是会占用内存的,那么当同时存在过多的canvas时,就会出现一个问题,页面卡顿甚至崩溃。所以,这是第二个原因。

那么这篇文章主要是解决第一个原因所带来的问题的。

编程!启动!

第一步

那么先简单的随便生成一个组件好了,因为是公司源码嘛,大家懂的都懂。

interface IProps {
  qrCode: string
  studentName: string
  className: string
}

const SaveQRCode = (props: IProps) => {
  const divRef = React.useRef<HTMLDivElement>(null)
  // 具体怎么渲染看你们需求了
  return (
    <div ref={divRef}>XXXXXX</div>  
  )
}

看到代码,用过html2canvas的小伙伴应该知道ref是干嘛用的了,html2canvas()这个方法的参数是HTMLElement,传统一点的办法呢,可以通过document.getXXXXX这个方法来获取真实的dom元素。那么Ref就是替代前者的,它可以直接通过react框架获取真实的dom元素。

第二步

那么最简单的组件我们已经写好了,接下来就是如何动态的挂载这个组件,并且在挂载完之后就立刻卸载它。

那么先来理一下思路: 1、动态地挂载这个组件,且不能被用户肉眼观察到 2、挂载动作执行完立刻执行html2canvas获取canvas对象 3、通过canvas对象转换成blob对象并返回,或者直接通过回调函数返回canvas对象 4、组件卸载,清空dom

那么根据上面几点,可以得出:从外部获取的肯定是有组件这个东西,而挂载的位置则有要求,但并不一定需要从外部获取。

为了不被样式影响,我们直接在body标签下,再挂载一个div标签,来进行组件的动态渲染和卸载,同时也避免了影响之前dom树的结构。

思路就说到这了,接下来直接抛出代码:

const AsyncMountComponent = (
  getElement: (onUnmount: () => void) => ReactNode,
  container: HTMLElement,
) => {
  const root = createRoot(container)
  const element = getElement(() => {
    root.unmount()
    container.remove()
  })
  root.render(<Suspense fallback={null}>{element}</Suspense>)
}

这里我因为想做的更加通用一点,所以把根节点让外部进行处理,如果希望更加业务一点,比如当前这个场景必然不会让用户可见,可以直接改成

const AsyncMountComponent = (getElement: (onUnmount: () => void) => ReactNode) => {
  const div = document.createElement('div')
  div.style.position = 'absolute'
  div.style.left = '2000px'
  document.body.appendChild(div)
  const root = createRoot(div)
  const element = getElement(() => {
    root.unmount()
    container.remove()
  })
  root.render(<Suspense fallback={null}>{element}</Suspense>)
}

这里的隐藏方式看个人喜好,无所谓。但有一点要注意的是,一定要可见,不然的话html2canvas生成不了图片,这里是最简单粗暴的方式,直接偏移left

第三步

那么地基打好了,我们该怎么用这两个东西呢

interface IProps {
  qrCode: string
  studentName: string
  className: string
  // 这里自然就是获取blob和canvas对象的地方了
  onConfirm?: (data: { canvas: HTMLCanvasElement, blob: Blob }) => void
  // 这里是卸载的地方,由外部决定何时卸载节点,更加自由
  onUnmount?: () => void
}

const SaveQRCode = (props: IProps) => {
  const divRef = React.useRef<HTMLDivElement>(null)
  useEffect(() => {
    if (divRef.current && props.onConfirm) {
      html2canvas(divRef.current).then((canvas) => {
        canvas.toBlob((blob) => {
          props.onConfirm!({canvas, blob: blob!})
          props.onUnmount!()
        })
      })
    }
  }, [])
  // 具体怎么渲染看你们需求了
  return (
    <div ref={divRef}>XXXXXX</div>  
  )
}

首先我们对组件进行修改,因为我的方案是第一种,没有太业务向,所以说一些业务逻辑必然是要到组件层面去处理的,所以添加两个参数,一个获取blobcanvas对象,另一个用来卸载节点。

至于useEffect就很容易理解了,挂载后用html2canvas处理组件顶层div获取截图,然后返回数据,并卸载节点。

组件改造完毕了,那我们接下来把这两个组合一下

const getQRCodeBlobCanvas = async (props: IProps): Promise<{
  canvas: HTMLCanvasElement, blob: Blob
}> => {
  return new Promise((resolve) => {
    const div = document.createElement('div')
    div.style.position = 'absolute'
    div.style.left = '2000px'
    document.body.appendChild(div)
    asyncMountComponent(
      (dispose) => (<SaveQRCode {...props} onConfirm={resolve} onUnmount={dispose}/>),
      div
    )
  })
}

那么一个简单的动态阅后即焚组件就完成了,且可以直接通过方法的形式使用,完美适配批量导出功能,当然也包括单个导出,至于批量导出的细节我就不写了,非常的简单。

升级V2

我只提供了最通用一种方式来做这么个阅后即焚组件,之后我闲着无聊,又把它做了一次业务向升级,获得了V2版本

这个版本呢,你只需要传入一个组件进去,且不用关心何时卸载,它是最真实的阅后即焚。至于数据,会通过Promise的方式返回给用户。

const Wrapper = ({callback, children}: {  
  callback: (data: { blob: Blob,canvas: HTMLCanvasElement }) => void,  
  children: ReactNode  
}) => {  
  const divRef = useRef<HTMLDivElement>(null)  
  useEffect(() => {  
    if (divRef.current) {  
      html2canvas(divRef.current).then((canvas) => {  
        canvas.toBlob((blob) => {  
          callback({canvas, blob: blob!})  
        })  
      })  
    }  
  }, [])  
  return <div ref={divRef}>  
    {children}  
  </div>
}  
  
const getComponentSnapshotBlobCanvas = (getElement: () => ReactNode): Promise<{canvas:HTMLCanvasElement, blob: Blob}> => {
  return new Promise((resolve) => {
    const div = document.createElement('div')
    div.style.position = 'absolute'
    div.style.left = '2000px'
    document.body.appendChild(div)
    const root = createRoot(div)
    root.render((
      <Wrapper
        callback={(values) => {
          root.unmount()
          div.remove()
          resolve(values)
        }}
      >
        {getElement()}
      </Wrapper>
    ))
  })
}

本文转载于:

https://juejin.cn/post/7278512641781334051

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

 记录--组件阅后即焚?挂载即卸载!看完你就理解了文章来源地址https://www.toymoban.com/news/detail-747587.html

到了这里,关于记录--组件阅后即焚?挂载即卸载!看完你就理解了的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • mac录屏软件推荐!相信我,看完你不会后悔

    有粉丝后台问小编,自己的电脑是mac电脑,不知道如何使用mac电脑录屏,有没有mac录屏软件推荐?小编之前也是用的Windows电脑进行录屏,后来换了mac,经过多年的摸索,熟练掌握了录屏方法。今天小编就带大家了解下有关Mac电脑的录屏方法,以及几款好用的录屏软件推荐。

    2024年02月08日
    浏览(47)
  • 电脑技巧:宽带怎么设置教程笔记,看完你就会了

    宽带的设置是指将计算机连接到互联网的过程。一般来说,宽带的设置是非常简单的,只需要按照提供商的要求,正确地连接硬件和软件就可以了。下面将详细介绍如何设置宽带。 硬件设置:首先,需要连接计算机和调制解调器,以及路由器(如果有的话)。通常,宽带提供

    2024年02月11日
    浏览(47)
  • ai绘画图片美女怎么画?看完你就知道了

    大家在刚开始接触文生图的AI绘画的时候,是不是会因为在输入描述词时不知道应该如何描述,而导致生成的图片都比较简单或者混乱,不符合自己的预期。 其实,我刚接触AI绘图也是这样的,不过经过我的探索,我用AI做的图越来越漂亮了,给大家欣赏一下。 那么大家想知

    2024年02月14日
    浏览(46)
  • SpringBoot整合OAuth2.0看完你就会了!

    OAuth 2.0是一种开放的授权协议,它允许用户授权第三方应用访问其账户(或资源),而无需共享其用户账户凭据。在Spring Boot中,我们可以使用Spring Security的OAuth2.0模块来实现授权验证。 好了到此为止,以上就是springboot整合ouath2.0的主要代码啦,欢迎大家在评论区留言讨论!

    2024年02月06日
    浏览(46)
  • 月薪6000在中国什么水平?看完你就不焦虑了

    今天刷到一个很扎心的问题:你对自己现在的收入满意吗? 多数人都是不假思索地反问:“怎么会满意……” 都说挣钱够用就行,谁又真正满意过。 镜头前的主播抱怨忙,却偷偷年收百万,00后副业月入10万,连知根知底的发小,也突然月入过万。 而你拼命不比谁少, 跑进

    2023年04月22日
    浏览(46)
  • 无线路由器为什么需要重启 看完你就知道

    无线路由器已经成为每个家庭中不可或缺的网络设备。使用WiFi网络,无论是上网刷微博,还是在线追剧,亦或是进行在线游戏,经常卡顿的现象是最让人受不了的。有时候WiFi连接不佳,拍两下路由器是没有效果的。我们会重启无线路由器,重启后明显会感觉的网络变得流畅

    2024年02月05日
    浏览(52)
  • 【Unity】Time.deltaTime有什么用?看完你就明白

    大多数刚开始使用 Unity 的人(包括我),都会对 Time.deltaTime 感到迷惑。 看完本文,你就会明白 Time.deltaTime的定义及作用。 根据定义, Time.deltaTime是每一帧之间的时间间隔 (以秒为单位)。 这有助于我们使游戏与帧数无关,也就是说,无论 fps 是多少,游戏都将以相同的速

    2024年02月16日
    浏览(45)
  • 电脑技巧:电脑关机、休眠、睡眠之间如何选择,看完你就懂了

    目录 一、关机、休眠、睡眠的区别? 1.关机 2.休眠   休眠的优点 休眠的缺点 3.睡眠   睡眠的优点 睡眠的缺点 二、什么时候关机/休眠/睡眠? 什么时候需要关机?  什么情况下使用休眠模式? 什么情况下使用睡眠模式? 三、终极建议 电脑技巧:电脑关机、休眠、睡眠之

    2024年01月15日
    浏览(50)
  • ai绘画生成的软件有哪些?看完你可能就知道了

    ai绘画是近年来新兴的一项技术,它可以通过机器学习和深度学习算法,让计算机自动地进行图像生成和绘画。 那么以下是ai绘画的好处: 第一:提高创作效率——传统的绘画需要耗费大量的时间和精力,而ai绘画可以快速生成各种类型的图像,大大提高了创作效率。 第二:

    2024年02月12日
    浏览(55)
  • 实不相瞒——看完你也能(10分钟内)手撸一个低代码框架

    工作中又遇到了低代码的研发工作,所以借此机会向大家分享下我的所思所考,大多数公司后期为了应对重复的中后台项目或H5等页面,为了更好的降本增效,低代码似乎成为了自研公司的前端团队的一把杀手锏。 或许很多程序员工作中用不到低代码平台,但是个人认为玩转

    2024年02月02日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包