您现在的位置是:网站首页 > <script>-客户端脚本文章详情

<script>-客户端脚本

<script> 标签是 HTML 中用于嵌入或引用客户端脚本的核心元素,通常用于实现动态交互、数据处理或页面行为控制。它支持多种脚本语言,但现代开发中主要使用 JavaScript。

<script> 标签的基本语法

<script> 标签可以直接在 HTML 文档中嵌入脚本代码,或通过 src 属性引用外部脚本文件。以下是两种常见写法:

<!-- 内联脚本 -->
<script>
  console.log("Hello, World!");
</script>

<!-- 外部脚本 -->
<script src="app.js"></script>

标签的 type 属性在 HTML5 中默认为 text/javascript,通常可省略。早期版本可能需要明确指定:

<script type="text/javascript">
  // 传统写法
</script>

脚本的加载行为

默认同步加载

默认情况下,浏览器会同步解析并执行 <script> 标签,这会阻塞 HTML 解析:

<script>
  document.write("这段内容会立即输出");
</script>
<p>这段文字会在脚本执行后显示</p>

异步加载模式

通过 asyncdefer 属性可以改变脚本加载行为:

<!-- 异步加载(下载不阻塞HTML解析,下载完成后立即执行) -->
<script async src="analytics.js"></script>

<!-- 延迟执行(下载不阻塞HTML解析,在DOMContentLoaded前执行) -->
<script defer src="ui.js"></script>

两者的区别:

  • async 脚本无序执行,适合独立模块
  • defer 脚本按文档顺序执行,适合依赖型脚本

动态脚本加载

通过 DOM API 动态创建脚本元素:

const script = document.createElement('script');
script.src = 'dynamic.js';
document.head.appendChild(script);

动态加载的脚本默认具有 async 行为,可以手动改为同步:

script.async = false;

模块化脚本

现代 JavaScript 支持模块系统,通过 type="module" 声明:

<script type="module">
  import { utils } from './utils.js';
  utils.log('模块已加载');
</script>

模块脚本默认具有 defer 特性,且支持跨域请求(需 CORS 配置):

<script type="module" crossorigin src="https://example.com/module.js"></script>

事件处理

<script> 标签支持加载事件回调:

<script src="big-file.js" onload="init()" onerror="handleError()"></script>

对应的 JavaScript 实现:

const script = document.createElement('script');
script.onload = () => console.log('脚本加载完成');
script.onerror = () => console.error('加载失败');
script.src = 'app.js';

数据块(Data Blocks)

非 JavaScript 内容可以通过自定义类型声明:

<script type="application/json" id="config">
{
  "apiUrl": "https://api.example.com",
  "timeout": 5000
}
</script>

<script>
  const config = JSON.parse(document.getElementById('config').text);
  console.log(config.apiUrl); // 输出API地址
</script>

性能优化实践

预加载关键资源

<link rel="preload" href="critical.js" as="script">

代码分割示例

配合现代打包工具实现按需加载:

// 动态导入模块
button.addEventListener('click', async () => {
  const module = await import('./dialog.js');
  module.open();
});

内联关键脚本

首屏关键脚本可直接内联以减少请求:

<script>
  // 内联的初始化代码
  (function(){
    const theme = localStorage.getItem('theme') || 'light';
    document.documentElement.className = theme;
  })();
</script>

安全注意事项

内容安全策略(CSP)

通过 HTTP 头限制脚本来源:

Content-Security-Policy: script-src 'self' https://trusted.cdn.com

防止内联脚本注入

避免拼接 HTML 字符串:

// 危险示例
element.innerHTML = `<script>maliciousCode()</script>`;

// 安全方案
const script = document.createElement('script');
script.textContent = 'safeCode()';
element.appendChild(script);

兼容性处理

传统浏览器降级

<script>
  // 现代特性检测
  if(!window.Promise) {
    document.write('<script src="polyfill.js"><\/script>');
  }
</script>

noscript 备用方案

<noscript>
  <style>.js-content { display: none }</style>
  <p>请启用JavaScript以获得完整功能</p>
</noscript>

调试技巧

源码映射配置

<script src="app.min.js" sourcemap="app.min.js.map"></script>

错误追踪示例

window.addEventListener('error', (e) => {
  console.error(`脚本错误: ${e.message} @ ${e.filename}:${e.lineno}`);
});

服务端渲染结合

在 Node.js 环境中动态注入脚本:

const serverData = { user: { name: 'Alice' } };
res.send(`
  <script>window.__INITIAL_STATE__ = ${JSON.stringify(serverData)}</script>
  <script src="client.js"></script>
`);

现代框架中的使用

React 示例

function App() {
  useEffect(() => {
    const script = document.createElement('script');
    script.src = "third-party.js";
    document.body.appendChild(script);
    
    return () => script.remove();
  }, []);
  
  return <div>内容区</div>;
}

Vue 示例

<template>
  <div>
    <script v-if="needsScript" src="component-dep.js"></script>
  </div>
</template>

<script>
export default {
  mounted() {
    loadScript('dynamic-dep.js').then(() => {
      this.initialize();
    });
  }
}
</script>

性能监控

测量脚本加载时间:

const script = document.createElement('script');
const start = performance.now();

script.onload = () => {
  const loadTime = performance.now() - start;
  console.log(`脚本加载耗时: ${loadTime.toFixed(2)}ms`);
};

script.src = 'analytics.js';
document.head.appendChild(script);

缓存控制策略

通过版本号管理缓存:

<script src="app.js?v=20230601"></script>

或使用文件指纹:

<script src="app.3a7b8c9.js"></script>

代码组织模式

IIFE 封装

<script>
  (function(global) {
    'use strict';
    // 私有作用域代码
    global.publicAPI = { ... };
  })(window);
</script>

命名空间模式

window.MYAPP = window.MYAPP || {};
MYAPP.utils = {
  formatDate(date) { /* ... */ }
};

与其它技术的协作

Web Workers 通信

<script>
  const worker = new Worker('task.js');
  worker.postMessage({ cmd: 'start' });
  worker.onmessage = (e) => console.log(e.data);
</script>

Web Components 集成

class MyElement extends HTMLElement {
  constructor() {
    super();
    const script = document.createElement('script');
    script.textContent = `console.log('元素已创建')`;
    this.appendChild(script);
  }
}
customElements.define('my-element', MyElement);

我的名片

网名:~川~

岗位:console.log 调试员

坐标:重庆市-九龙坡区

邮箱:cc@qdcc.cn

沙漏人生

站点信息

  • 建站时间:2013/03/16
  • 本站运行
  • 文章数量
  • 总访问量
微信公众号
每次关注
都是向财富自由迈进的一步