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

Node.js+Vite项目动态加载页面JS无法生效问题求助

问题描述

正在开发基于Node.js、原生JS和Vite的前后端训练项目,启动时加载index.html和app.js,由app.js动态加载其余页面。当前遇到两个核心问题:

  1. 动态加载的页面中引入的JS文件无法生效
  2. 若将这些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,提问作者Дмитрий Бояркин

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 20:06:00