直接在 HTML 中嵌入(不推荐用于生产环境)

这是最直接的方法,直接在 HTML 文件中使用 <script> 标签包裹你的 JS 代码。

网页加载自己的js代码
(图片来源网络,侵删)

内联脚本

直接在 HTML 文件中写 <script>

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">内联脚本示例</title>
</head>
<body>
    <h1>你好,世界!</h1>
    <button id="myButton">点击我</button>
    <!-- 直接在这里写 JS 代码 -->
    <script>
        // 当整个 HTML 文档被完全加载和解析完成后执行
        document.addEventListener('DOMContentLoaded', function() {
            const button = document.getElementById('myButton');
            button.addEventListener('click', function() {
                alert('按钮被点击了!');
                console.log('按钮点击事件被触发。');
            });
            console.log('内联 JS 脚本已执行。');
        });
    </script>
</body>
</html>

优点:

  • 简单直接,无需额外的文件请求。

缺点:

  • 可维护性差:HTML 和 JS 代码混在一起,文件会变得臃肿且难以阅读。
  • 无法缓存:浏览器不会缓存内联脚本,每次访问页面都需要重新下载和解析整个 HTML 文件。
  • 作用域问题:容易污染全局命名空间。

内部脚本

将 JS 代码放在一个单独的 <script> 标签中,但仍然在 HTML 文件内部。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">内部脚本示例</title>
</head>
<body>
    <h1>你好,世界!</h1>
    <button id="myButton">点击我</button>
    <!-- 引用同一 HTML 文件中的脚本 -->
    <script>
        // 和上面内联脚本一样的代码
        document.addEventListener('DOMContentLoaded', function() {
            const button = document.getElementById('myButton');
            button.addEventListener('click', function() {
                alert('按钮被点击了!');
            });
        });
    </script>
</body>
</html>

这种方式和内联脚本缺点类似,只是代码位置不同,同样不推荐用于项目开发。

网页加载自己的js代码
(图片来源网络,侵删)

外部链接文件(最推荐的方式)

这是现代 Web 开发的标准做法,将你的 JavaScript 代码保存在一个独立的 .js 文件中,然后在 HTML 中通过 <script> 标签的 src 属性来引用它。

步骤 1:创建 JS 文件

在你的项目文件夹中,创建一个 scripts 文件夹,并在其中创建一个 app.js 文件。

scripts/app.js

// 当整个 HTML 文档被完全加载和解析完成后执行
document.addEventListener('DOMContentLoaded', function() {
    const button = document.getElementById('myButton');
    if (button) { // 增加一个判断,以防元素不存在
        button.addEventListener('click', function() {
            alert('按钮被点击了!');
            console.log('按钮点击事件被触发。');
        });
    }
    console.log('外部 JS 文件 (app.js) 已加载并执行。');
});

步骤 2:在 HTML 中引用

在你的 HTML 文件中,使用 <script src="..."></script> 来引入这个 JS 文件。

index.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">外部脚本示例</title>
</head>
<body>
    <h1>你好,世界!</h1>
    <button id="myButton">点击我</button>
    <!-- 引用外部的 JS 文件 -->
    <!-- 
      最佳实践:将 script 标签放在 body 结束标签之前。
      这样可以确保 HTML 内容先被加载和解析,JS 执行时所需的 DOM 元素已经存在。
    -->
    <script src="scripts/app.js"></script>
</body>
</html>

优点:

  • 关注点分离:HTML 负责结构,CSS 负责样式,JS 负责行为,代码清晰,易于维护。
  • 可重用性:同一个 JS 文件可以被多个 HTML 页面引用。
  • 浏览器缓存:浏览器会缓存 .js 文件,当用户访问你的网站的其他页面时,如果也引用了这个 JS 文件,浏览器会直接从缓存中读取,加快加载速度。
  • 团队协作友好:不同开发者可以分别负责 HTML、CSS 和 JS 文件,避免冲突。

缺点:

  • 需要发起一个额外的 HTTP 请求来下载 JS 文件(但现代浏览器通常会并行下载,并且有缓存机制,影响很小)。

使用模块系统(现代大型项目的最佳实践)

如果你的项目变得复杂,你可能需要使用 JavaScript 模块,模块允许你将代码分割成多个小文件,每个文件都可以导出(export)特定的变量、函数或类,然后由其他文件导入(import)使用。

步骤 1:创建模块化的 JS 文件

假设你的功能比较复杂,你想把按钮相关的逻辑和工具函数分开。

scripts/utils.js (工具模块)

// 导出一个简单的工具函数
export function logMessage(message) {
    console.log(`[工具模块] ${message}`);
}

scripts/buttonHandler.js (按钮处理模块)

// 从 utils.js 导入 logMessage 函数
import { logMessage } from './utils.js';
function setupButton() {
    const button = document.getElementById('myButton');
    if (button) {
        button.addEventListener('click', function() {
            alert('模块化按钮被点击了!');
            logMessage('模块化按钮点击事件被触发。');
        });
    }
}
// 导出这个函数,让主文件可以调用
export { setupButton };

步骤 2:在 HTML 中引入模块

要使用模块,你的 HTML 文件需要做一些特殊配置:

  1. <script> 标签必须添加 type="module" 属性。
  2. 路径建议使用相对路径(以 、 或 开头)。

index.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">模块化脚本示例</title>
</head>
<body>
    <h1>你好,世界!</h1>
    <button id="myButton">点击我</button>
    <!-- 
      type="module" 告诉浏览器这是一个 ES 模块。
      浏览器会自动处理模块的依赖关系,并按正确的顺序执行。
    -->
    <script type="module" src="scripts/main.js"></script>
</body>
</html>

还需要一个主入口文件来组织模块:

scripts/main.js (主模块)

// 导入我们需要的模块
import { setupButton } from './buttonHandler.js';
import { logMessage } from './utils.js';
// 执行初始化
document.addEventListener('DOMContentLoaded', function() {
    logMessage('主模块开始执行。');
    setupButton();
});

优点:

  • 代码组织性极强:将复杂应用拆分成小块,易于管理和维护。
  • 避免命名冲突:每个模块都有自己的作用域,不会污染全局命名空间。
  • 依赖关系清晰importexport 让模块间的依赖关系一目了然。
  • 按需加载:配合现代打包工具(如 Vite, Webpack),可以实现代码分割和按需加载,进一步提升性能。

缺点:

  • 配置相对复杂,通常需要配合构建工具(如 Vite, Webpack)在开发环境中使用。
  • 直接在浏览器中使用模块时,需要注意 CORS(跨域资源共享)策略。

总结与最佳实践

方法 优点 缺点 适用场景
内联/内部脚本 简单、快速 可维护性差、无法缓存、易冲突 非常简单的测试、一次性脚本、或为了 SEO 优化而内联关键 JS。
外部链接文件 关注点分离、可重用、可缓存、易于维护 需要额外请求 绝大多数 Web 项目的标准做法。
模块系统 代码组织性强、避免冲突、依赖清晰、利于大型项目 配置复杂,需构建工具支持 大型、复杂、需要长期维护的 Web 应用程序。

给新手的建议:

  1. 从“外部链接文件”开始:这是最基础、最重要、最应该掌握的方式,90% 的项目场景下,这已经足够好。
  2. 学习模块系统:当你写的项目越来越大,文件越来越多时,一定要学习 ES 模块,这是现代前端开发的必备技能。
  3. 了解 <script> 标签的 deferasync 属性
    • async:异步下载,下载完成后立即执行,可能会打乱页面渲染顺序,适合独立的脚本,如分析工具。
    • defer:异步下载,但会在整个 HTML 解析完毕后、DOMContentLoaded 事件之前按顺序执行。这是将 <script> 放在 <head> 中的最佳选择。
    • 无属性:默认同步执行,会阻塞 HTML 解析。推荐放在 </body> 前,效果等同于 defer

最佳实践代码结构:

my-project/
├── index.html
├── css/
│   └── style.css
└── js/
    └── app.js

index.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">我的项目</title>
    <link rel="stylesheet" href="css/style.css">
    <!-- JS 不依赖 DOM 结构,可以放在 head 中并使用 defer -->
    <!-- <script src="js/app.js" defer></script> -->
</head>
<body>
    <!-- 页面内容 -->
    <script src="js/app.js"></script>
</body>
</html>