延迟加载JavaScript脚本?

3

有没有一种方法可以包装外部JS脚本嵌入懒加载行为,以便只在嵌入视口中时执行?

背景: 我有一个外部javascript嵌入,在运行时生成一个带有调度小部件的iframe。工作得很好,除了当脚本执行时,它会窃取焦点并将您向下滚动到小部件。供应商已经寻找解决方法几个星期了,但它正在破坏我的页面。我否则很喜欢供应商。

Javascript嵌入调用:

<a href=https://10to8.com/book/zgdmlguizqqyrsxvzo/ id="TTE-871dab0c-4011-4293-bee3-7aabab857cfd" target="_blank">See
    Online Booking Page</a>
<script src=https://d3saea0ftg7bjt.cloudfront.net/embed/js/embed.min.js> </script> <script>
    window.TTE.init({
        targetDivId: "TTE-871dab0c-4011-4293-bee3-7aabab857cfd",
        uuid: "871dab0c-4011-4293-bee3-7aabab857cfd",
        service: 1158717
    });
</script>

当我等待供应商修复他们的JS时,我想知道是否延迟加载JS嵌入可以实际上消除糟糕的用户体验。警告:我是JS / webdev新手,所以可能无法做任何复杂的事情。基于计时器的解决方法并不理想,因为当计时器运行完毕时,用户可能仍在查看页面的其他部分。以下是我尝试过的事情及其发生的情况:
我尝试过的事情: 发生了什么: 将async添加到上述一个或两个脚本声明中 要么只显示链接,要么一直抢占焦点。 将type =“module”添加到上述一个或两个脚本声明中 只呈现了链接。 使用适当的延迟加载标签将上述代码包装在iframe中 当我尝试时,它呈现为空白空间。
此外,我意识到这基本上与this相同的问题,但它没有得到任何可行的答案。

2
这将是一个多步骤的过程,您需要做出一些决策。您可以编写一些 JavaScript 代码来检测用户何时滚动到特定点或何时某个元素进入视口,然后才将<script src=..插入到您的 DOM 中。查看此 API - TKoL
2
这个回答解决了你的问题吗?当用户将元素滚动到视口中时触发函数 - Vanilla JavaScript - Heretic Monkey
但是这样做的问题在于,如果你等待太久,那么当代码运行和脚本加载时,他们可能已经滚动过了那个点。 - TKoL
嗨 Dylan,这应该会帮助你...... https://dev59.com/43NA5IYBdhLWcg3wdtr5 或 https://dev59.com/7V0a5IYBdhLWcg3wsKi2 - fuzzybear
你可以尝试使用 https://creativelive.github.io/appear/ 这个JS库,它可以帮助你触发JS代码来 A) 创建script标签,以在页面中加载供应商的脚本(只需使用一个变量即可),然后 B) 根据<a>标签的属性构建init参数,并调用init函数。 - Patrick Janser
2个回答

1

我其实也会说法语,但是为了大家我会用英语回答。

你的问题非常有趣,因为我也想尝试一些懒加载,所以我在 Codepen 上使用了你的示例(使用你的预订 ID)进行了一番尝试。

我使用了 appear.js 库,因为我不想花时间尝试其他 API(也许更轻量级需要考虑)。

我编写的主要 JS 部分如下:

// The code to init the appear.js lib and add our logic for the booking links.
(function(){
  // Perhaps these constants could be put in the generated HTML. I don't really know
  // where they come from but they seem to be related to an account.
  const VENDOR_LIB_SRC = "https://d3saea0ftg7bjt.cloudfront.net/embed/js/embed.min.js";
  const UUID = "871dab0c-4011-4293-bee3-7aabab857cfd";
  const SERVICE = 1158717;
  
  let vendorLibLoaded = false; // Just to avoid loading several times the vendor's lib.

  appear({
    elements: function() {
      return document.querySelectorAll('a.booking-link');
    },
    appear: function(bookingLink) {
      console.log('booking link is visible', bookingLink);
      
      /**
       * A function which we'll be able to execute once the vendor's
       * script has been loaded or later when we see other booking links
       * in the page.
       */
      function initBookingLink(bookingLink) {
        window.TTE.init({
          targetDivId: bookingLink.getAttribute('id'),
          uuid: UUID,
          service: SERVICE
        });
      }
      
      if (!vendorLibLoaded) {
        // Load the vendor's JS and once it's loaded then init the link.
        let script = document.createElement('script');
        script.onload = function() {
          vendorLibLoaded = true;
          initBookingLink(bookingLink);
        };
        script.src = VENDOR_LIB_SRC;
        document.head.appendChild(script);
      } else {
        initBookingLink(bookingLink);
      }
    },
    
    reappear: false
  });
})();

我让你在这里试用我的 CodePen:https://codepen.io/patacra/pen/gOmaKev?editors=1111

如果其中包含敏感数据,请告诉我何时删除它!

此致敬礼,

Patrick


嗨@Dylan!我看了你的Drupal页面55,但我没有看到appear.js被加载。你是否创建了一个自定义模块来添加压缩的appear.js库和一些使用传统的Drupal.behaviors运行初始化代码的自定义JS?正如你在我的codepen上看到的,我为这些链接添加了一个CSS类。如果你使用a[id] CSS/jQuery选择器选择链接,你可能会得到一些其他不需要的链接。 - Patrick Janser
@Dylan:我在你的联系页面中找到了“meet”小部件。我不确定,但似乎<a id="...">标签和<script>标签来加载供应商JS库直接在页面内容中。这不是真正的Drupal方式。最好编写一个Drupal模块,实现一个过滤器,以便它查找<a class="booking-link" ...>标签,然后加载appear.js和负责加载供应商embed.js并调用init函数的自定义JS。 - Patrick Janser
谢谢,但是它好像没有生效?在这里可以看到测试页面:https://simple-salt.com/node/53。appear.js和您提供的代码(lazy_10to8.js)已经加载。正如您所看到的 - <a id="[id]"> 没有被替换。 - Dylan
@Dylan:如果你查看JS控制台,你会发现出现了这个错误:Uncaught ReferenceError: appear is not defined。这是因为appear.js要么丢失了,要么是在使用它的自定义代码之后加载的。你可以将appear.js和自定义代码放在同一个JS文件中,这样就不会出现错误了。我还注意到带有预订链接的HTML id属性中有一些空格:id=" TTE-871dab0c-4011-4293-bee3-7aabab857cfd " target=" _ blank "。最好也纠正一下,否则供应商库可能无法找到该ID,因为它具有不必要的空格。 - Patrick Janser
我找到了答案。根本原因是RocketLoader搞乱了这些额外的js库(但其他的没有??),导致它们无法运行。禁用它后,一切都完美地运作了。感谢您的耐心和帮助。那个出现的库相当不错。 - Dylan
显示剩余4条评论

0

这种方法只会在用户可见时进行惰性加载 HTML 元素,如果该元素未滚动到视口中,则不会被加载,它的工作方式就像惰性加载图像一样。

LazyHTML 脚本添加到 Head 中。

<script async src="https://cdn.jsdelivr.net/npm/lazyhtml@1.0.0/dist/lazyhtml.min.js" crossorigin="anonymous" debug></script>

将元素包装在LazyHTML包装器中。

<div class="lazyhtml" data-lazyhtml onvisible>
<script type="text/lazyhtml">
      <!--
       <a href=https://10to8.com/book/zgdmlguizqqyrsxvzo/ id="TTE-871dab0c-4011-4293-bee3-7aabab857cfd" target="_blank">See
      Online Booking Page</a>
      <script src=https://d3saea0ftg7bjt.cloudfront.net/embed/js/embed.min.js>
   </script> 
   <script>
      window.TTE.init({
      targetDivId: "TTE-871dab0c-4011-4293-bee3-7aabab857cfd",
      uuid: "871dab0c-4011-4293-bee3-7aabab857cfd",
      service: 1158717
      });
   </script>
   -->
</script>
</div>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接