/ Nuxt.js

#Vue或Nuxt.js页面中动态加载js文件

问题背景

如果把项目中的一些功能打包成js文件,以sdk的方式提供给前端页面使用,这样,在sdk更新时不需要重新打包部署项目,大大降低了耦合度,提高了灵活性。

在直接使用html编写web项目时,通过在html文件中添加<script>标签来引入js文件,可以非常简单实现这个功能。

但是,在Nuxt.js项目中,要如何实现呢?

Nuxt.js的页面,其实就是一个Vue页面,所以这个问题就变成了:如何在Vue页面中引入一个远程js文件?

一个Vue页面包含3个部分:

  • template
  • script
  • style

template虽然看起来是html代码,但是实际上,Vue并不允许在template中使用script标签。

参考:《Vue加载器细则》 https://vue-loader-v14.vuejs.org/zh-cn/start/spec.html

那么有什么办法呢?

解决方法

这个问题的解决方法很多,例如:

  • 1). 使用vue应用的模板文件app.html,如果你的sdk需要在所有的页面里使用,可以用这种方式。这种方法是个全局方案,灵活度很差。
  • 2). 动态创建script元素实现动态加载。这种方法的灵活度就好很多。
  • 3). 还有其他方法就不一一介绍了。

本文注意介绍第2种方案。其中,动态加载js文件的代码可以参考:

《#JavaScript 根据需要动态加载脚本并设置自定义参数》
https://xmanyou.com/javascript-dynamically-load-script-and-set-parameters/

代码有了,那么要添加在Vue页面的什么地方呢?这就需要了解一下Vue应用的生命周期:

参考:

nuxtjs-lifecycle

可以看到,mounted方法是最早最适合添加动态js代码的地方。

注意事项

  • 1). created方法时,document还没有被创建,所以无法用来动态加载代码。
  • 2). 与普通html页面不同,由于vue的特性,mounted中动态加载js脚本,即使没有设置async异步加载,也不会在下一行代码之前加载完成,所以,需要添加onload方法来判定js脚本是否加载完毕,之后才能进行相关操作。

参考代码

所以,vue页面的参考代码如下:

<template>

</template>

<script>
  mounted():{
    const sdkUrl = "<sdk 地址>";
    this.loadJsAsync(sdkUrl)
    .then(()=>{
        console.info("加载成功");
    })
    .catch(e=>{
        console.error("加载失败", e);
    });
  },

  methods:{
    // 动态加载js库文件
    loadJsAsync(src, async, options){
      return new Promise((resolve, reject) => {
        const script = document.createElement("script");
        script.src = src;
        script.async = async;
        if (options) {
          for (const key in options) {
            script.setAttribute(key, options[key]);
          }
        }

        const onload = () => {
          console.info("js loaded: ", src);
          script.removeEventListener("load", onload);
          
          resolve();
        };

        script.addEventListener("load", onload);
        script.addEventListener("error", (err) => {
          script.removeEventListener("load", onload);
          console.error("loading js error: ", src, err);
          reject(new Error(`Failed to load ${src}`));
        });

        (
          document.getElementsByTagName("head")[0] || document.documentElement
        ).appendChild(script);

      });
    },
  }

</script>

参考