admin管理员组

文章数量:1332896

Is there a way I can wrap an external JS script embed with lazy-load behavior to only execute when the embed is in the viewport?

Context: I have an external javascript embed that when run, generates an iframe with a scheduling widget. Works pretty well, except that when the script executes, it steals focus and scrolls you down to the widget when it’s done executing. The vendor has been looking at a fix for a couple weeks, but it’s messing up my pages. I otherwise like the vendor.

Javascript embed call:

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

While I'm waiting for the vendor to fix their js, I wondered if lazy-loading the JS embed may practically eliminate the poor user experience. Warning: I'm a JS/webdev noob, so probably can't do anything plicated. A timer-based workaround is not ideal because users may still be looking at other parts of the page when the timer runs out. Here are the things I’ve tried and what happens:

I tried: What happened:
Add async to one or both of the script declarations above Either only shows the link or keeps stealing focus.
Adding type=”module” to one or both script declarations above Only rendered the link.
Wrapping the above code in an iframe with the appropriate lazy-loading tags When I tried, it rendered a blank space.

Is there a way I can wrap an external JS script embed with lazy-load behavior to only execute when the embed is in the viewport?

Context: I have an external javascript embed that when run, generates an iframe with a scheduling widget. Works pretty well, except that when the script executes, it steals focus and scrolls you down to the widget when it’s done executing. The vendor has been looking at a fix for a couple weeks, but it’s messing up my pages. I otherwise like the vendor.

Javascript embed call:

<a href=https://10to8./book/zgdmlguizqqyrsxvzo/ id="TTE-871dab0c-4011-4293-bee3-7aabab857cfd" target="_blank">See
    Online Booking Page</a>
<script src=https://d3saea0ftg7bjt.cloudfront/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>

While I'm waiting for the vendor to fix their js, I wondered if lazy-loading the JS embed may practically eliminate the poor user experience. Warning: I'm a JS/webdev noob, so probably can't do anything plicated. A timer-based workaround is not ideal because users may still be looking at other parts of the page when the timer runs out. Here are the things I’ve tried and what happens:

I tried: What happened:
Add async to one or both of the script declarations above Either only shows the link or keeps stealing focus.
Adding type=”module” to one or both script declarations above Only rendered the link.
Wrapping the above code in an iframe with the appropriate lazy-loading tags When I tried, it rendered a blank space.

Also, I realize it's basically the same question as this, but it didn't get any workable answers.

Share Improve this question asked May 11, 2021 at 13:08 DylanDylan 531 gold badge1 silver badge3 bronze badges 5
  • 2 This would be a multi-step process and you'd have to make some decisions. You can write some javascript to detect when the user has scrolled to a certain point, or when a certain element es in the viewport, and only then insert the <script src=.. into your dom. check out this api – TKoL Commented May 11, 2021 at 13:16
  • 2 Does this answer your question? Trigger a function when the user scrolls the element into the viewport – Vanilla JavaScript – Heretic Monkey Commented May 11, 2021 at 13:17
  • But the problem with this is that if you wait too long, then they may have scrolled past that point by the time the code runs and the script loads. – TKoL Commented May 11, 2021 at 13:17
  • Hi Dylan, this should help you out .... stackoverflow./questions/950087/… or stackoverflow./questions/30033152/… – fuzzybear Commented May 11, 2021 at 13:23
  • You may could try out creativelive.github.io/appear which is a JS lib that can help you trigger the JS code to A) create the script tag which will load the vendor's script in the page (use a variable to do it only once) and then B) call the init function with the init params which you can build based on the attributes of the <a> tag. – Patrick Janser Commented May 11, 2021 at 13:28
Add a ment  | 

2 Answers 2

Reset to default 1

I actually also speak french but I'll reply in english for everybody.

Your question was quite interesting because I also wanted to try out some lazy loading so I had a play on Codepen with your example (using your booking id).

I used the appear.js library because I didn't really want to spend time trying some other APIs (perhaps lighter so to take in consideration).

The main JS part I wrote is like this:

// 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 e from but they seem to be related to an account.
  const VENDOR_LIB_SRC = "https://d3saea0ftg7bjt.cloudfront/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
  });
})();

I let you try my codepen here: https://codepen.io/patacra/pen/gOmaKev?editors=1111

Tell me when to delete it if it contains sensitive data!

Kind regards,

Patrick

This method will Lazy Load HTML Elements only when it is visible to User, If the Element is not scrolled into viewport it will not be loaded, it works like Lazy Loading an Image.

Add LazyHTML script to Head.

<script async src="https://cdn.jsdelivr/npm/[email protected]/dist/lazyhtml.min.js" crossorigin="anonymous" debug></script>

Wrap Element in LazyHTML Wrapper.

<div class="lazyhtml" data-lazyhtml onvisible>
<script type="text/lazyhtml">
      <!--
       <a href=https://10to8./book/zgdmlguizqqyrsxvzo/ id="TTE-871dab0c-4011-4293-bee3-7aabab857cfd" target="_blank">See
      Online Booking Page</a>
      <script src=https://d3saea0ftg7bjt.cloudfront/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>

本文标签: Lazyload a javascript scriptStack Overflow