Node.js+Vite项目动态加载页面JS无法生效问题求助
问题描述
正在开发基于Node.js、原生JS和Vite的前后端训练项目,启动时加载index.html和app.js,由app.js动态加载其余页面。当前遇到两个核心问题:
- 动态加载的页面中引入的JS文件无法生效
- 若将这些JS直接引入
index.html,会因目标DOM未加载完成,导致document.getElementById无法正常工作
已尝试调整静态文件配置、移除客户端Vite,问题仍未解决。相关代码如下:
服务器代码
import express from 'express' import cors from 'cors' import { router } from './router/index.js' import { connectToDatabase } from './db/index.js' import { success, error, info } from './utils/chalk.js' import socketController from './socket/socket.js' import { Server } from 'socket.io' import http from 'http' import 'dotenv/config' import path from 'path'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); // creating express app/server const app = express() const server = http.createServer(app) const io = new Server(server, { cors: { origin: 'http://localhost:3000' } }) const port = process.env.PORT || 5000 app.use(express.static(path.join(__dirname, '../client'))); app.get('/', (req, res) => { res.send('${path.join(__dirname, "../client/index.html")}'); }); // enabling application/json headers app.use(express.json()) // enabling cors policy app.use(cors({ origin: process.env.CLIENT_ORIGIN_URI, methods: ["POST", "PUT", "GET", "DELETE", "OPTIONS"], })) // http://localhost:5000 app.use('/api/flights', router.flightRouter) app.use('/api/passengers', router.passengerRouter) app.use('/api/airports', router.airportRouter) app.use('/api/planes', router.planeRouter) app.use('/api/admins', router.adminRouter) // socket io connetions io.on('connection', socketController) // Connecting to the database connectToDatabase() .then(() => console.log(success("[database] [success] Connected to database"))) .catch(() => console.log(error("[database] [error] Doesn't connected to database"))) // starting up the server server.listen(port, () => { console.log(success(`[server] [success] Server has been started... \n[server] [success] URL: http://localhost:${port}`)) })
index.html代码
<!doctype html> <html lang="ru"> <head> <meta charset="UTF-8" /> <link rel="icon" type="image/svg+xml" href="/favicon.svg" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>URTK Airport Panel</title> <link rel="stylesheet" href="src/index.css"> <script type="module" src="src/app.js" defer></script> </head> <body> <div id="root"></div> </body> </html>
app.js代码
import axios from 'axios'; async function loadPageWithAxios(href) { try { const response = await axios.get(href); return response.data; } catch (error) { console.error('Ошибка при загрузке страницы:', error); throw error; } } // renderApp.js import AuthPage from './pages/AuthPage/AuthPage.html'; function renderApp() { const isAuthorized = !!localStorage.getItem('token') && !!localStorage.getItem('fullName') && !!localStorage.getItem('admin-type'); const rootElement = document.getElementById('root'); let routing; if (!isAuthorized) { loadPageWithAxios('src/test.html') .then(html => { rootElement.innerHTML = html; }) .catch(error => { console.error('Ошибка при загрузке страницы:', error); }); } else { loadPageWithAxios(AuthPage) .then(html => { rootElement.innerHTML = html; }) .catch(error => { console.error('Ошибка при загрузке страницы:', error); }); } } window.onload = renderApp;
AuthPage.html代码
<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Вход</title> <link rel="stylesheet" href="/public/css/AuthPage.css"> <script type="text/javascript" src="/admin/public/js/AuthPage.js" defer></script> </head> <body> <div class="auth"> <div class="auth__container" id="authContainer"> <div class="auth__container__header"> <div class="header__company-logo">URTK Airport</div> <div class="header__container-name">Вход</div> </div> <form class='auth__form' id="authForm"> <div class="auth__form__item"> <div class="item__title">Ваше ФИО</div> <input type="text" class="item__input" id="fullNameInput" placeholder='Иванов Иван Иванович' /> </div> <div class="auth__form__item"> <div class="item__title">Ваш пароль</div> <input type="password" class="item__input" id="passwordInput" placeholder='Пароль' /> </div> <div class="auth__form__item"> <div class="item__title">Секретное слово</div> <input type="password" class="item__input" id="secretWordInput" placeholder='Секретное слово' /> </div> <button class='send-data-button' type='button' id="submitButton" >Войти</button> </form> <div id="loadingSpinner" class="hidden">Loading...</div> </div> </div> </body> </html>
解决方案
1. 修复动态加载页面JS不生效的问题
浏览器通过innerHTML插入HTML时,不会自动执行其中的<script>标签,需要手动提取并执行脚本。修改app.js的页面加载逻辑:
import axios from 'axios'; async function loadPageWithAxios(href) { try { const response = await axios.get(href); return response.data; } catch (error) { console.error('Ошибка при загрузке страницы:', error); throw error; } } function renderPage(html, rootElement) { rootElement.innerHTML = html; // 提取并执行插入的脚本 const scripts = rootElement.querySelectorAll('script'); scripts.forEach(oldScript => { const newScript = document.createElement('script'); // 复制原脚本的所有属性 Array.from(oldScript.attributes).forEach(attr => { newScript.setAttribute(attr.name, attr.value); }); // 处理内联脚本内容 if (oldScript.textContent) { newScript.textContent = oldScript.textContent; } // 替换旧脚本触发执行 oldScript.parentNode.replaceChild(newScript, oldScript); }); } function renderApp() { const isAuthorized = !!localStorage.getItem('token') && !!localStorage.getItem('fullName') && !!localStorage.getItem('admin-type'); const rootElement = document.getElementById('root'); const targetUrl = !isAuthorized ? 'src/test.html' : './pages/AuthPage/AuthPage.html'; loadPageWithAxios(targetUrl) .then(html => renderPage(html, rootElement)) .catch(error => console.error('Ошибка при рендере страницы:', error)); } window.onload = renderApp;
注意:移除import AuthPage from './pages/AuthPage/AuthPage.html'的写法,直接使用文件路径更稳定,避免移除Vite后出现语法错误。
2. 解决DOM未加载导致getElementById失效的问题
如果要将页面JS放在index.html中,确保代码在目标DOM渲染完成后执行,有两种可行方式:
方式一:监听DOM加载完成事件
在页面JS中包裹所有依赖DOM的代码:
document.addEventListener('DOMContentLoaded', () => { const submitButton = document.getElementById('submitButton'); if (submitButton) { submitButton.addEventListener('click', () => { // 处理登录逻辑 }); } });
方式二:动态导入页面JS模块
在页面渲染完成后,动态导入对应页面的JS:
在renderPage函数末尾添加:
// 根据页面URL判断是否加载AuthPage的JS if (targetUrl.includes('AuthPage')) { import('/admin/public/js/AuthPage.js') .then(module => { // 如果模块有导出的初始化函数,调用它 if (module.init) module.init(); }) .catch(error => console.error('Ошибка при загрузке AuthPage.js:', error)); }
同时修改AuthPage.js,将逻辑封装为初始化函数:
export function init() { const submitButton = document.getElementById('submitButton'); // 绑定事件、表单处理等逻辑 }
3. 服务器端路径修复
当前服务器根路由返回的是路径字符串,而非实际HTML文件,修改为:
app.get('/', (req, res) => { res.sendFile(path.join(__dirname, "../client/index.html")); });
内容的提问来源于stack exchange,提问作者Дмитрий Бояркин
相关产品推荐
相关产品推荐

