#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应用的生命周期:
参考:
可以看到,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>