浏览器 API 你可能不知道的实用功能

浏览器 API 你可能不知道的实用功能

Web API 越来越丰富,有些 API 虽然不常被提及,但在实际开发中能省不少事。这篇文章整理了一些 2025 年已经可以放心使用的浏览器 API。

Clipboard API

复制到剪贴板终于不需要 Flash 或 execCommand 了:

// 复制文本
await navigator.clipboard.writeText('Hello World');

// 读取剪贴板
const text = await navigator.clipboard.readText();

// 复制富文本(HTML)
await navigator.clipboard.write([
  new ClipboardItem({
    'text/html': new Blob(['<b>Bold</b> text'], { type: 'text/html' }),
    'text/plain': new Blob(['Bold text'], { type: 'text/plain' }),
  }),
]);

注意:需要在用户交互(点击、按键)的回调里调用,否则浏览器会拒绝。

Intersection Observer

检测元素是否进入视口,替代 scroll 事件监听:

const observer = new IntersectionObserver(
  (entries) => {
    entries.forEach((entry) => {
      if (entry.isIntersecting) {
        console.log('元素进入视口', entry.target);
        observer.unobserve(entry.target); // 只触发一次
      }
    });
  },
  { threshold: 0.1 } // 10% 可见时触发
);

observer.observe(document.querySelector('.lazy-image'));

典型用途:懒加载图片、无限滚动、曝光统计。

ResizeObserver

监听元素尺寸变化(不是窗口尺寸):

const resizeObserver = new ResizeObserver((entries) => {
  for (const entry of entries) {
    const { width, height } = entry.contentRect;
    console.log(`元素尺寸: ${width}x${height}`);
  }
});

resizeObserver.observe(document.querySelector('.container'));

window.resize 精确——可以监听任意 DOM 元素的尺寸变化,不只是窗口。

Performance Observer

监听长任务(Long Tasks),超过 50ms 的任务会阻塞主线程:

const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    console.log(`长任务: ${entry.duration}ms`, entry.name);
  }
});

observer.observe({ entryTypes: ['longtask'] });

这个 API 对于排查页面卡顿很有用。如果发现频繁出现长任务,就需要考虑拆分计算、使用 Web Worker 或 requestIdleCallback。

structuredClone

深拷贝对象,替代 JSON.parse(JSON.stringify()):

const original = {
  date: new Date(),
  regex: /test/g,
  map: new Map([['key', 'value']]),
  set: new Set([1, 2, 3]),
  nested: { arr: [1, 2, 3] },
};

const cloned = structuredClone(original);

// JSON.parse(JSON.stringify()) 丢失 Date、RegExp、Map、Set
// structuredClone 完整保留

structuredClone 能正确处理 Date、RegExp、Map、Set、ArrayBuffer、Blob 等类型。缺点是不能克隆函数和 DOM 节点。

AbortController

取消网络请求和任何可取消的异步操作:

const controller = new AbortController();

// 取消 fetch 请求
fetch('/api/data', { signal: controller.signal });

// 取消 EventSource
const es = new EventSource('/api/stream');
es.addEventListener('message', handler);
// 关闭时
es.close();

// 5 秒后取消
setTimeout(() => controller.abort(), 5000);

在 React 里用 AbortController 清理副作用:

useEffect(() => {
  const controller = new AbortController();

  fetch('/api/data', { signal: controller.signal })
    .then(res => res.json())
    .then(setData);

  return () => controller.abort();
}, []);

URL Pattern API

匹配 URL 路径,比正则表达式更直观:

const pattern = new URLPattern('/posts/:id', 'https://example.com');

pattern.test('https://example.com/posts/123'); // true
pattern.exec('https://example.com/posts/123');
// { id: '123', ... }

在 Service Worker 里用这个 API 做路由匹配很方便。

View Transitions API

页面切换动画,原生 API:

// 触发页面过渡动画
document.startViewTransition(() => {
  // 更新 DOM
  updateContent();
});

浏览器会自动在新旧页面之间做动画(淡入淡出)。可以配合 CSS 自定义动画效果:

::view-transition-old(root) {
  animation: fade-out 0.2s ease-out;
}

::view-transition-new(root) {
  animation: fade-in 0.2s ease-in;
}

SPA 路由切换时加这个,体验提升很大。

File System Access API

读写本地文件,可以做一个简单的"打开文件"和"保存文件"功能:

// 打开文件
const [fileHandle] = await window.showOpenFilePicker();
const file = await fileHandle.getFile();
const content = await file.text();

// 保存文件
const fileHandle = await window.showSaveFilePicker({
  suggestedName: 'document.txt',
});
const writable = await fileHandle.createWritable();
await writable.write('Hello World');
await writable.close();

浏览器安全限制比较多(需要 HTTPS、用户手势触发),但功能确实强大。可以用来做在线编辑器的本地文件支持。

注意兼容性

这些 API 在 Chrome 里的支持都很好,Safari 和 Firefox 对部分 API 支持较晚:

API Chrome Safari Firefox
Clipboard 66+ 13.1+ 63+
IntersectionObserver 51+ 12.1+ 55+
ResizeObserver 64+ 13.1+ 69+
structuredClone 98+ 15.4+ 94+
View Transitions 111+ 18+ 未支持
File System 86+ 15.2+ 未支持

用之前查一下 caniuse,对不支持的浏览器做好降级处理。

这些 API 都是浏览器原生提供的,不需要任何第三方库。掌握了它们,很多以前需要依赖库才能实现的功能现在几行代码就能搞定。

TypeScriptReact
返回首页