Vanilla JS单页应用中动态插入的脚本仅执行一次的问题求助
Vanilla JS单页应用中动态插入的脚本仅执行一次的问题求助
我正在用Node.js + Express搭建一个原生JS的单页应用,折腾了好几个小时,翻遍了各种资料和Stack Overflow,还是解决不了动态插入的脚本只执行一次的问题…下面是出现问题的简化项目结构,希望有人能帮忙看看。
项目代码片段
index.html(主页面)
<!DOCTYPE html> <html lang="en"> <head> <script src='../scripts/index.js' type='module' defer></script> </head> <body> <nav> <a href='/testA' class='route'>Test A</a> <a href='/testB' class='route'>Test B</a> </nav> <div id='views'></div> </body> </html>
TestA.html(示例视图页面)
<!DOCTYPE html> <html lang="en"> <head> <script src='../scripts/TestA.js' type='module' defer></script> </head> <body> <p> View: Test A </p> </body> </html>
TestA.js(视图对应的脚本)
const obj = {name: 'A', val: '000'} console.log(obj)
核心路由逻辑 index.js
const nav = document.querySelectorAll('.route') for (const element of nav){ element.addEventListener('click', (event) => { event.preventDefault() history.pushState(null, '', element.href) spaRouting() }) } const container = document.getElementById('views') function spaRouting(){ const path = window.location.pathname const html = '...' // 这里实际是从Node服务器获取HTML文件的fetch请求 container.innerHTML = html const oldScripts = container.getElementsByTagName('script') for (const oldScript of oldScripts){ const newScript = document.createElement('script') for(const attribute of oldScript.attributes){newScript.setAttribute(attribute.name, attribute.value)} newScript.addEventListener('load', () => console.log('script was loaded')) oldScript.replaceWith(newScript) } } window.addEventListener('popstate', spaRouting())
问题现象
路由跳转和HTML注入都完全正常,在TestA和TestB之间来回切换时,HTML内容能正常更新。
- 第一次切换到TestA的时候,TestA.js里的代码会执行,控制台能打印出
{name: 'A', val: '000'}; - 但第二次及之后再切回TestA时,虽然HTML内容依旧更新,而且脚本元素的
load事件也触发了(控制台能看到"script was loaded"),但TestA.js里的代码就是不执行了。
我已经尝试过的解决方案
- 先把新脚本标签追加到DOM,再移除旧的,而不是用
replaceWith/replaceChild - 手动给新脚本设置属性,而不是从旧脚本复制属性
- 给每个脚本标签设置唯一ID,确保每次插入的脚本ID都不一样
- 把新脚本追加到index.html的head或body里,再移除容器里的旧脚本
但这些方法都没用,而且我不能把所有脚本都预加载到index.html里——实际项目中很多脚本依赖对应视图里的DOM元素,这些元素只有在视图加载后才存在(项目是从多页应用迁移过来的)。
真的快搞不定了,希望有人能解释这个现象,再给个可行的修复方案😭
备注:内容来源于stack exchange,提问作者Unfrosted9025
相关产品推荐
相关产品推荐

