javascript - 如何使用事件监听器加载 javascript 文件
问题描述
这个问题不是重复的
也不是这个
我已经经历了它们,它们与我想做的有点相似,但并不完全相同。以下是在上述问题中,用户只想根据条件加载脚本文件一次。但就我而言,我想根据点击事件加载不同的 js 文件。
所以在我的例子中,我有一个 HTML 文档:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Experiment</title>
<link href="s.css" rel="stylesheet" type="text/css">
</head>
<body>
<div class="navigation">
<nav>
<ul>
<li id="home_btn"> Home</li>
<li id="about_btn"> About </li>
</ul>
</nav>
</div>
<canvas id="myCanvas">
</canvas>
<div class="notePane">
<p> This is just a bunch of text not explanation</p>
</div>
</body>
<script src="./exp.js" type="text/javascript"></script>
</html>
这个 h.html 文件链接到一个 exp.js 文件。现在在 exp.js 文件中:
var h_btn = document.getElementById("home_btn");
var a_btn = document.getElementById("about_btn");
var head = document.getElementsByTagName("head")[0];
var js = document.createElement("script");
js.type="module";
h_btn.addEventListener("click", showHome );
a_btn.addEventListener("click", showAbout);
function showHome() {
js.src="./j1.js";
head.appendChild(js);
}
function showAbout() {
js.src="./j2.js";
head.appendChild(js);
}
因此,当我单击网页上的 h_btn 时,一切正常。它加载 j1.js。但是当我点击网页上的 a_btn 时,我希望看到 j2.js 链接,但我没有看到它。我必须刷新页面,然后单击 a_btn 以查看链接的 j2.js。如何链接 j1.js 和 j2.js,这样我就不必一次又一次地刷新页面来加载正确的脚本。
解决方案
更新:OP 更新了问题要求,以便在单击另一个 JS 文件时“卸载”一个 JS 文件。一旦加载了 JS 文件,就无法撤消所有运行时逻辑:唯一的方法是重新加载页面。删除<script>
标签或更改src
属性不会神奇地取消绑定事件侦听器或“取消声明”变量。
因此,如果 OP 想要“重新开始”,唯一的方法是检查之前是否加载了自定义脚本:如果有,我们强制重新加载页面。当然,有很多方法可以“通知”下一页要加载哪个源(如果可用):在下面的示例中,我们使用查询字符串:
var h_btn = document.getElementById("home_btn");
var a_btn = document.getElementById("about_btn");
var head = document.getElementsByTagName("head")[0];
var appendedScriptKey;
var scripts = {
'home': './j1.js',
'about': './j2.js'
}
h_btn.addEventListener("click", showHome);
a_btn.addEventListener("click", showAbout);
// Check query string if a specific script is set
var params = (new URL(document.location)).searchParams;
var scriptKey = params.get('scriptKey');
if (scriptKey && scriptKey in scripts) {
appendScript(scriptKey);
}
function appendScript(key) {
if (hasAppendedScript) {
location.href = location.href + (location.search ? '?' : '&') + 'script=' + key;
location.reload();
}
var js = document.createElement("script");
js.type="module";
js.src = scripts[key];
head.appendChild(js);
appendedScript = key;
}
function showHome() {
appendedScriptKey('home');
}
function showAbout() {
appendScript('about');
}
这是因为如何Node.appendChild()
工作。第一次单击有效,因为您正在创建一个新元素并将其插入到您的文档中。但是,第二次点击不会像您预期的那样工作,因为节点已经存在:
该
Node.appendChild()
方法将一个节点添加到指定父节点的子节点列表的末尾。如果给定的子节点是对文档中现有节点的引用,appendChild()
则将其从当前位置移动到新位置
这意味着第二次点击只会改变src
已经注入<script>
元素的属性,而不是创建一个新的,这也意味着第二个脚本src不会被加载。
一个解决方案是使用一个每次都会创建一个脚本标签的函数:
var h_btn = document.getElementById("home_btn");
var a_btn = document.getElementById("about_btn");
var head = document.getElementsByTagName("head")[0];
h_btn.addEventListener("click", showHome);
a_btn.addEventListener("click", showAbout);
function insertScript(src) {
var js = document.createElement("script");
js.type = "module";
js.src = src;
head.appendChild(js);
}
function showHome() {
insertScript('./j1.js');
}
function showAbout() {
insertScript('./j2.js');
}
但这也意味着多次点击同一个按钮会导致脚本被多次注入。这不会对浏览器性能产生太大影响,因为浏览器将加载的脚本缓存在某处,但为了防止这种情况,最好为每个脚本实现某种唯一标识符,并在注入之前检查它。有很多方法可以做到这一点,这只是一种方法:
var h_btn = document.getElementById("home_btn");
var a_btn = document.getElementById("about_btn");
var head = document.getElementsByTagName("head")[0];
h_btn.addEventListener("click", showHome);
a_btn.addEventListener("click", showAbout);
// Store scripts that you've injected
var scripts = [];
function insertScript(src) {
// If we have previously attempted injection, then do nothing
if (scripts.indexOf(src) !== -1) {
return;
}
var js = document.createElement("script");
js.type = "module";
js.src = src;
head.appendChild(js);
// Push script to array
scripts.push(src);
}
function showHome() {
insertScript('./j1.js');
}
function showAbout() {
insertScript('./j2.js');
}
替代独特的脚本注入策略和想法:
- 使用ES6
Map()
跟踪被注入的独特脚本源 src
脚本成功加载后,可能只存储到数组/dict/map
推荐阅读
- r - 如何根据条件找到后续试验?
- java - 如果选项卡具有不同大小的组件,如何将 JTabbedPane 中的选项卡打包到框架的大小?
- python - Python自动将一些字符串转换为原始字符串?
- android - Google Map 文本样式在 Android 上的显示与样式向导中的不同
- python - 如何修复此凯撒密码以包含大写字母?
- python - 我可以使用 python 以特定字体绘制单词吗?
- mysql - 开发基于 Web 的实时仪表板
- python - 传递要加密的变量 Fernet Python
- kubernetes - 如何使用 Minikube 设置 imagePullPolicy
- docker - 我们可以在构建镜像之前计算 docker 镜像摘要以检查 docker 注册表吗?