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

时间:2017-04-30 14:55:57

标签: javascript html image printing lazy-loading

有些网站有很多图片,因此延迟加载似乎适合减少加载时间和数据消耗。但是,如果您还需要支持该网站的打印,该怎么办?

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

HTML

<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7">

注意:这是一个一个像素的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';
    }
  })
});

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

注意:对于obvious reasons onbeforeprintonafterprint,我没有感到烦恼。

如果图像被缓存,这将正常工作,但再次确切地说点。图像应全部加载,然后出现在打印屏幕中。

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

更新

我在检测到打印对话框后尝试将用户重定向到标准版本的网站website.com?print=true,其中停用了延迟加载并且所有图片都正常加载。

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

重要说明:此方法已在Chrome中测试过,但在Firefox和Edge中无效(因此,这不是答案,而是证词)。

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

4 个答案:

答案 0 :(得分:13)

根据您所需的功能,我不太清楚您想要做什么是可行的。作为开发人员,我们无法真正控制用户浏览器。以下是关于为什么这不完全可能的想法。

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

  2. 您无法stall or stop打印电话 - 您无法强制浏览器等待您的图片在延迟加载环境中完成加载。 (我读过一些关于使用警报实现这一点的事情,但对我来说它似乎真的很笨拙,对打印来说更像是一种威慑而不是拖延)

  3. 您无法强制img.src在延迟加载上下文中同步获取该数据。有一些方法可以做到这一点,但它们是clever hacks -- referenced as pure evil,可能无法始终有效。我找到了another link with a similar approach

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

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

    您几乎可以完成同步XMLHttpRequest。 Syncrhonous XMLHTTPRequests不允许您更改responseType,它们始终是字符串。但是,您可以将字符串值转换为arrayBuffer将其编码为base-64编码的字符串,并将src设置为dataURL(请参阅引用聪明黑客的链接) - 但是,当我尝试这个时,我收到了一个错误the 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;
    }
    

    努力改善用户体验

    您可以执行的操作是在页面的打印版本中显示一些文字(通过@print css媒体),其中显示&#34;图片仍在加载,取消您的打印请求并重试# 34;当图像完成加载时,删除那个&#34;仍在等待资源再次尝试消息&#34;来自DOM。更进一步,你可以将主内容包装在一个反转显示的元素内,当没有加载内容时,所以你看到的就是打印预览对话框中的那条消息。

    关闭您发布的代码可能如下所示(请参阅更新的jsfiddle):

    <强> CSS

    .printing-not-ready-message{
      display:none;
    }
    @media print{
      .printing-not-ready-message{
        display:block;
      }
      .do-not-print-content{
        display:none;
      }
    }
    

    <强> 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>
    

    <强>的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=""
          }
        }
      })
    });
    

答案 1 :(得分:2)

我是vanilla-lazyload脚本的作者,我最近开发了一种功能,可以打印所有图像!

使用this repo codelive here测试了跨浏览器。

看看,让我知道您的想法! 我愿意在GitHub上拉请求。

答案 2 :(得分:0)

我编写了一个延迟加载jquery插件,支持使用window.onbeforeprint事件和mediaQueryListeners在打印时显示图像。 https://github.com/msigley/Unveil-EX/

答案 3 :(得分:0)

对于和我一样的人来说:当使用浏览器原生 loading="lazy" 时,您可以在打印即将发生时简单地删除该属性。下面是我的 jQuery 实现。

window.onbeforeprint = function () {
  $('img').each(function () {
    $(this).removeAttr('loading')
  });
}

Chrome 将只加载所有图像,并在打印时显示。