You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 08:33:07