繁体   English   中英

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

[英]How to lazy load images and make them available for print

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

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

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 )。

注意:出于明显的原因,我没有打扰onbeforeprintonafterprint

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

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

更新

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

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

重要提示:此方法在 Chrome 中进行了测试,它在 Firefox 和 Edge 中都不起作用(因此这不是答案,而是见证)。

它在 Chrome 中有效,因为当您重定向到另一个网站时打印对话框会关闭(在这种情况下,相同的 url 但已标记)。 在 Edge 和 Firefox 中,打印对话框是一个实际的窗口,它不会关闭它,因此非常不可用。

根据您想要的功能,我不太确定您想要做的事情是否可行。 作为开发人员,我们并不能真正控制用户的浏览器。 以下是我对为什么这不完全可能的想法。

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

  2. 你不能停止或停止打印调用——你不能强迫浏览器等待你的图像在延迟加载上下文中完成加载。 (我曾经读过一些关于使用警报来实现这一点的东西,但它对我来说似乎真的很老套,更多的是对打印的威慑而不是拖延)

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

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

潜在的解决方案(灵感来自第三点中的链接以及此链接

您几乎可以通过同步 XMLHttpRequest 侥幸逃脱。 同步 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;
}

解决问题以增强用户体验

您可以做的事情是在页面的打印版本中显示一些文本(通过@print css 媒体),上面写着“图像仍在加载,取消您的打印请求并重试”,当图像完成加载时,删除来自 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=""
      }
    }
  })
});

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

使用这里repo 代码测试跨浏览器。

看看,让我知道你的想法! 我当然愿意在 GitHub 上拉取请求。

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

//declare custom onbeforeprint method
const customOnBeforePrint = () => {
    const smoothScroll = (h) => {
        let i = h || 0;
        if (i < 200) {
            setTimeout(() => {
                window.scrollTo(window.scrollY, window.scrollY + i);
                smoothScroll(i + 10);
            }, 10);
        }
    };

    let height = document.body.scrollHeight;
    let newHeight;
    while (true) {
        smoothScroll(100);

        if (newHeight === height) break;
        height = newHeight;
    }
};

//override the onbeforeprint method
window.onbeforeprint = customOnBeforePrint;

将该块复制并粘贴到 devtool 的控制台中,然后尝试单击打印按钮。 该解决方法对我有用。

对于与我在同一条船上的人:当使用浏览器本机loading="lazy"时,您可以在打印时简单地删除该属性。 下面是我的 jQuery 实现。

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM