简体   繁体   English

使用 vanilla js 按需加载脚本文件

[英]Load script file on demand with vanilla js

I use an accordion or tabs.我使用手风琴或标签。 When clicking on a tab, I want to display a map or something that require a big javascript file to load.单击选项卡时,我想显示地图或需要加载大 javascript 文件的内容。

To not load the big javascript when it is not needed, I want to load it only when the tab is clicked.为了在不需要时不加载大 javascript,我只想在单击选项卡时加载它。

How can I do that?我怎样才能做到这一点? I've created a good starting point with accordion and a click event.我用手风琴和点击事件创建了一个很好的起点。

  • I use vanilla js (pure javascript - no jQuery)我使用 vanilla js(纯 javascript - 没有 jQuery)
  • I use it on a webpage (not nodejs)我在网页上使用它(不是 nodejs)
  • I'm fine if it works with modern browsers (IE not needed)如果它适用于现代浏览器,我很好(不需要 IE)

 window.addEventListener('DOMContentLoaded', () => { document.querySelector('[data-trigger]').addEventListener('click', () => { console.log('Load script from file'); // CDN example - https://cdnjs.cloudflare.com/ajax/libs/mapbox-gl/1.12.0/mapbox-gl.js }); });
 ul { list-style: none; margin: 0; padding: 0; } label { display: flex; align-items: center; } label:before { content: ''; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' d='M0 0h24v24H0z'/%3E%3Cpath d='M13.172 12l-4.95-4.95 1.414-1.414L16 12l-6.364 6.364-1.414-1.414z'/%3E%3C/svg%3E"); background-repeat: no-repeat; width: 24px; height: 24px; } input[type=checkbox] { display: none; } input[type=checkbox]:checked ~ h2 label:before { transform: rotate(90deg); } p { display: none; } input[type=checkbox]:checked ~ h2 ~ p { display: block; }
 <ul> <li> <input type="checkbox" id="faq-1"> <h2 data-trigger> <label for="faq-1">Click to load map</label> </h2> <p>Gummies marzipan croissant chupa chups.</p> </li> <li> <input type="checkbox" id="faq-2"> <h2> <label for="faq-2">Something else</label> </h2> <p>Cookie bear claw carrot cake croissant.</p> </li> </ul>

You could dynamically create a script tag and add it to the document whenever the button is pressed.您可以动态地创建一个脚本标签,并在按下按钮时将其添加到文档中。 This will trigger the script to immediately be loaded.这将触发脚本立即加载。 With the onload callback you can run your code, like creating a map, the moment the script has actually loaded.使用onload回调,您可以在脚本实际加载的那一刻运行您的代码,例如创建地图。

Do add { once: true } as the third parameter for addEventListener as it will ensure that the trigger can only be clicked once and won't be able to append the script more than once.添加{ once: true }作为addEventListener的第三个参数,因为它将确保触发器只能被单击一次并且不能多次附加脚本。

function createMap() {
  const map = new mapboxgl.Map({
    ...
  });
}

window.addEventListener('DOMContentLoaded', () => {
  document.querySelector('[data-trigger]').addEventListener('click', () => {
    console.log('Load script from file');
    
    const script = document.createElement('script');
    script.id = 'mapboxgljs';
    script.src = 'https://cdnjs.cloudflare.com/ajax/libs/mapbox-gl/1.12.0/mapbox-gl.js'
    script.async = true;
    script.onload = function() {
      console.log('script loaded, you can use it now.');
      createMap();
    }
    document.body.append(script);
  }, { once: true }); // Make sure that the button can only be pressed once.
});

As you're comfortable with only supporting modern browsers, you could use the dynamic import() function to load the file:由于您对仅支持现代浏览器感到满意,因此您可以使用动态import()函数来加载文件:

 window.addEventListener('DOMContentLoaded', () => { document.querySelector('[data-trigger]').addEventListener('click', async() => { const module = await import('https://cdnjs.cloudflare.com/ajax/libs/mapbox-gl/1.12.0/mapbox-gl.js'); console.log(`module is loaded: ${Object.keys(mapboxgl)}`); }); });
 ul { list-style: none; margin: 0; padding: 0; } label { display: flex; align-items: center; } label:before { content: ''; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' d='M0 0h24v24H0z'/%3E%3Cpath d='M13.172 12l-4.95-4.95 1.414-1.414L16 12l-6.364 6.364-1.414-1.414z'/%3E%3C/svg%3E"); background-repeat: no-repeat; width: 24px; height: 24px; } input[type=checkbox] { display: none; } input[type=checkbox]:checked~h2 label:before { transform: rotate(90deg); } p { display: none; } input[type=checkbox]:checked~h2~p { display: block; }
 <ul> <li> <input type="checkbox" id="faq-1"> <h2 data-trigger> <label for="faq-1">Click to load map</label> </h2> <p>Gummies marzipan croissant chupa chups.</p> </li> <li> <input type="checkbox" id="faq-2"> <h2> <label for="faq-2">Something else</label> </h2> <p>Cookie bear claw carrot cake croissant.</p> </li> </ul>

import() returns a promise which is resolved on successful fetch, and resolves immediately on subsequent calls (in my testing), so you wouldn't have to deal with that specifically. import()返回一个在成功获取时解析的承诺,并在后续调用中立即解析(在我的测试中),因此您不必专门处理它。

For your specific mapbox-gl script, the value returned won't be useful, as the script isn't written as an ES6 module, but the side-effects of the script running will be in place (in this case, the mapboxgl variable being assigned onto globalThis ).对于您的特定mapbox-gl脚本,返回的值将没有用,因为该脚本不是作为 ES6 模块编写的,但脚本运行的副作用将就位(在这种情况下, mapboxgl变量被分配到globalThis )。 In scenarios where the loaded script is a module (using export correctly), you can use the resolved value directly to avoid polluting the global namespace.在加载的脚本为模块的场景下(正确使用export ),可以直接使用解析后的值,避免污染全局命名空间。

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

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