如何延迟加载图像并使其可用于打印

und*_*ned 24 html javascript printing lazy-loading image

有些网站有很多图像,所以延迟加载似乎适合减少加载时间和数据消耗.但是如果你还需要支持该网站的打印呢?

我的意思是,您可以尝试检测打印事件,然后加载图像,如下所示:

HTML

<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7">
Run Code Online (Sandbox Code Playgroud)

注意:这是一个一个像素的gif虚拟图像.

JavaScript的

window.addEventListener('DOMContentLoaded', () => {
  img = document.querySelector('img');
  var isPrinting = window.matchMedia('print');
  isPrinting.addListener((media) => {
    if (media.matches) {
      img.src = 'http://unsplash.it/500/300/?image=705';
    }
  })
});
Run Code Online (Sandbox Code Playgroud)

注意:如果您在代码游乐场中尝试此操作,请删除该DOMContentLoaded事件(或简单地分叉这些:JSFiddle | Codepen).

注:我没有事件与麻烦onbeforeprint,并onafterprint明显的原因.

如果图像被缓存,这将工作正常,但再次,这恰恰不是重点.图像应全部加载,然后出现在打印屏幕中.

你有什么想法?有没有人成功实现了打印就绪的延迟加载插件?

更新

我已经尝试在检测到打印对话框后将用户重定向到网站的标记版本,即website.com?print=true停用延迟加载并且所有图像正常加载.

通过window.print()在该标记的打印就绪版本的页面中应用该方法,在所有图像加载完成后打开新的打印对话框,并在页面顶部同时显示"等待"消息来改进该方法.

重要提示:此方法已在Chrome中进行过测试,但在Firefox和Edge中无效(因此,这不是一个答案,而是一个证词).

它适用于Chrome,因为当您重定向到另一个网站时,打印对话框会关闭(在这种情况下,相同的网址会被标记).在Edge和Firefox中,打印对话框是一个实际的窗口,它不会关闭它,使其无法使用.

Art*_*org 13

根据您所需的功能,我不太确定您想要做什么是可行的.作为开发人员,我们实际上无法控制用户浏览器.以下是我为什么不完全可能的想法.

  1. 挂钩事件去加载你丢失的图像不会让你保证图像会从服务器进入你的页面.更具体地说,为您的打印预览生成的PDF将在您的图像加载完成之前生成,这img.src = "..."是异步的.onbeforeprint不幸的是,你也会遇到类似的问题.有时候它有效,有时它不起作用(例如,在safari中测试时你的小提琴有效,但在Chrome中没有)

  2. 您无法停止或停止打印调用 - 您无法强制浏览器等待您的图像在延迟加载上下文中完成加载.(我读过一些关于使用警报来实现这一点的东西,但对我来说它似乎真的很笨拙,对打印更有威慑力而不是拖延)

  3. 您无法强制img.src在延迟加载上下文中同步获取该数据.有一些方法可以做到这一点,但它们是聪明的黑客 - 被称为纯粹的邪恶,可能永远不会起作用.我找到了另一个类似方法的链接

所以我们遇到了一个问题,如果在打印事件被触发时没有加载图像,我们就不能强制浏览器等到它们完成.当然,我们可以在打印时获取这些图像,但如上所述,我们不能等到弹出打印预览之前加载这些资源.

潜在的解决方案(灵感来自第三点和链接中的链接)

您几乎可以完成同步XMLHttpRequest.Syncrhonous XMLHTTPRequests不允许您更改responseType,它们始终是字符串.但是,您可以将字符串值转换为arrayBuffer将其编码为base-64编码的字符串,并将src设置为dataURL(请参阅引用聪明黑客的链接) - 但是,当我尝试这个时,我收到了一个错误jsfiddle - 所以如果事情配置正确,理论上是可能的.我很犹豫是否可以说是的,因为我无法使用下面的小提琴(但这是你可以探索的路线!).

var xhr = new XMLHttpRequest();
xhr.open("GET","http://unsplash.it/500/300/?image=705",false);
xhr.send(null);
if (request.status === 200) {
    //we cannot change the resposne type in synchronous XMLHTTPRequests
    //we can convert the string into a dataURL though
    var arr = new Uint8Array(this.response);
    // Convert the int array to a binary string
    // We have to use apply() as we are converting an *array*
    // and String.fromCharCode() takes one or more single values, not
    // an array.
    var raw = String.fromCharCode.apply(null,arr);

    // This is supported in modern browsers
    var b64=btoa(raw);
    var dataURL="data:image/jpeg;base64,"+b64;
    img.src = dataURL;
}
Run Code Online (Sandbox Code Playgroud)

努力改善用户体验

您可以做的事情是有一些文本只显示在您的页面的打印版本(通过@printcss媒体),显示"图像仍在加载,取消您的打印请求并再试一次",当图像加载完毕后,删除"还在等待资源再次尝试消息"来自DOM.更进一步,当未加载内容时,您可以将主要内容包装在反转显示的元素内,因此您只能在打印预览对话框中看到该消息.

关闭你发布的代码可能看起来像下面这样(参见更新的jsfiddle):

CSS

.printing-not-ready-message{
  display:none;
}
@media print{
  .printing-not-ready-message{
    display:block;
  }
  .do-not-print-content{
    display:none;
  }
}
Run Code Online (Sandbox Code Playgroud)

HTML

<div class="printing-not-ready-message">
Images are still loading please cancel your preview and try again shortly.
</div>
<div class="do-not-print-content">
    <h1>Welcome to my Lazy Page</h1>
    <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7">
    <p>Insert some comment about picture</p>
</div>
Run Code Online (Sandbox Code Playgroud)

JavaScript的

window.addEventListener('DOMContentLoaded', () => {
  img = document.querySelector('img');
  var isPrinting = window.matchMedia('print');
  isPrinting.addListener((media) => {
    if (media.matches) {
      img.src = 'http://unsplash.it/500/300/?image=705';
      //depending on how the lazy loading is done, the following might
      //exist in some other call, should happen after all images are loaded.
      //There is only 1 image in this example so this code can be called here.
      img.onload = ()=>{
          document.querySelector(".printing-not-ready-message").remove();
          document.querySelector(".do-not-print-content").className=""
      }
    }
  })
});
Run Code Online (Sandbox Code Playgroud)

  • 非常完整的答案,如果没有其他人提出建议,您将获得赏金。无论如何,+ 1。 (2认同)