猿问

如何在 iframe 加载后从缓存中读取它的*原始*源

最通用的描述方式是,我只想在客户端看到视口的某一部分后仅触发一个网络请求,然后以最有效的方式使用它并在 iframe 中显示它。


给定一个 DOM 结构如下:


<!DOCTYPE html>

<html>

  <head />

  <body>

    ...

    <iframe loading="lazy" sandbox="" src="http://www.example.com" />

    <pre />

    ...

  </body>

</html>

我想在标签中向客户展示上述pre内容的来源iframe。该iframe元素可以承载任意文档,它可以是文本的或二进制的,所知道的是浏览器可以显示它。iframe 的源 URL 托管在同一源上。


我的目标是通过访问 Chromium“view-source:”URL 或类似的 URL 来显示人们会看到的内容。


访问.contentWindow或.contentdocument属性可能是不可能的,因为它完全是沙盒的,但即使我可以,文档的也outerHTML不够,并且使用 anXMLSerializer显然会改变输出。另外,我相信浏览器可以编辑文档的某些区域,例如不必要的空格或格式。


我只是尝试了以下方法:


document

.body

.querySelector("iframe")

.addEventListener(

    "load",

    async ( { currentTarget: { src } } ) => {

        const data = await fetch(

            src, {

                cache: "only-if-cached"

            }

        );


        // ... use data

    }, {

        passive: true,

        once: true

    }

);

然而,获取失败。该 URL 似乎不在浏览器的缓存中,但我不想发起新的网络请求,有没有一种有效的方法可以做到这一点?


我正在考虑使用 Intersection Observer 作为一种潜在的解决方案,因为它只会导致一个网络请求,但代码相当长,而且它似乎无法正常工作(我对观察者缺乏经验)。


DIEA
浏览 189回答 1
1回答

海绵宝宝撒

事件侦听器和获取请求可能会发生一些潜在的情况。其他读者请注意,截至撰写本文时(2020 年 11 月),仅 Chrome/Chromium、Edge 和 Opera 支持 iframe 中的延迟加载。这个答案针对的是还想使用延迟加载来动态加载内容的提问者。如果只关心发出单个网络请求,则可以通过 fetch 请求并src通过 Blob 或数据 URI 或通过 或使用 Service Workers 设置 iframe 来完成srcdoc(下面将对此进行探讨)。添加事件侦听器之前可能加载的帧您可以在声明框架后将事件侦听器添加到框架中,如果在评估脚本之前加载框架(如果已缓存,则可能会出现这种情况),这可能会产生问题。contentWindow通常,您可以通过或属性查看您的框架是否已加载contentDocument,如果是,则在这些框架上运行初始化代码,但由于该框架是沙盒的,因此无法访问这些属性。相反,您可以做的是提前声明您的处理程序,然后在创建 iframe 时声明它:async function loader(frame) {    console.log(frame.src);    // ...}<iframe src="frame.html" loading="lazy" sandbox="" onload="loader(this)"></iframe>在获取请求中使用同源根据 MDN,only-if-cached只能在mode设置为 时使用same-origin,这在您的情况下应该没问题,因为您说框架是同源的。获取请求将类似于:await fetch(src, { mode: 'same-origin', cache: 'only-if-cached' });结果main.html<!doctype html><html>  <head>    <meta charset="utf-8" />    <style>      .spacer {        height: 200vh;        background: lightgray;        text-align: center;      }    </style>    <script>      async function loader(frame) {        var sourceCodeElementId = frame.dataset.code;        var sourceCodeElement = document.getElementById(sourceCodeElementId);        var response = await fetch(frame.src, {          mode: 'same-origin',          cache: 'only-if-cached'        });        if (response.status === 504) {          // if it didn't load via cache, just get it normally          response = await fetch(frame.src);        }        var text = await response.text();        sourceCodeElement.textContent = text;      }    </script>  </head>  <body>    <div class="spacer">Scroll Down</div>    <iframe src="frame.html"        loading="lazy"        data-code="frame-source-code"        sandbox=""        onload="loader(this)">    </iframe>    <pre id="frame-source-code"></pre>  </body></html>样本frame.html<!doctype html><html>Frame</html>可选/替代地使用 Service Worker如果问题是围绕网络请求,您可以使用Service Workers,作为上述修复的替代方案或补充。让它们启动并运行需要一些工作,但它们可以让您更好地控制网络请求。缓存文件是一个常见的教程,因此如果您走这条路,您应该能够找到相当数量的资源。
随时随地看视频慕课网APP

相关分类

JavaScript
我要回答