20个浏览器原生API帮你干掉一堆npm依赖
做前端项目,遇到需求第一反应经常是打开终端敲 npm install。复制文本装个库,弹窗装个库,懒加载装个库,深拷贝再装一个。
其实这些年浏览器已经内置了不少能力,很多小需求根本不需要额外装东西。这篇文章按项目里常见的场景,整理20个可以直接上手的原生API。每个都给一段最小代码,挑你最常用的那几个先试起来。
一、用户交互类
1. Clipboard API:复制文本不用 clipboard.js
做复制链接、邀请码、命令的场景很多,以前要装库,现在直接用 navigator.clipboard:
async function copyText(text) {
await navigator.clipboard.writeText(text);
console.log('copied');
}
copyText('npm create vite@latest');两个前提要注意:页面得跑在 HTTPS 或 localhost 上,而且通常要用户点击才能触发。写按钮事件最稳:
button.addEventListener('click', async () => {
await navigator.clipboard.writeText(location.href);
});这个 API 从 2020 年 3 月起在所有浏览器中可用,现在基本不用操心兼容问题。
2. Web Share API:调起系统分享面板
很多 H5 页面只是想拉起系统的分享功能,没必要接一堆第三方 SDK:
async function sharePage() {
if (!navigator.share) return;
await navigator.share({
title: document.title,
text: '这篇文章不错',
url: location.href,
});
}桌面端和部分浏览器不一定支持,按钮可以按能力隐藏:
shareButton.hidden = !navigator.share;二、弹层与对话框
3. Popover API:轻量弹层不用自己管层级
菜单、气泡卡片、更多操作面板,可以先看看 popover:
<button popovertarget="menu">更多</button>
<div id="menu" popover>
<button>编辑</button>
<button>删除</button>
</div>它会自动处理显示、隐藏和顶层展示,不用再手写 z-index: 9999。Popover API 自 2025 年 1 月起在所有现代浏览器中可用。
有一点要区分清楚:Popover API 创建的是非模态弹层,显示时页面其他部分仍可交互。如果你需要模态弹窗(背景不可操作),应该用下面的 <dialog> 元素。
4. Dialog:确认框和表单弹窗的正经解法
如果你还在用 div 模拟模态框,<dialog> 可以帮你省掉大量焦点管理代码:
<dialog id="confirmDialog">
<p>确认删除这条记录吗?</p>
<button value="cancel">取消</button>
<button value="ok">删除</button>
</dialog>const dialog = document.querySelector('#confirmDialog');
deleteButton.addEventListener('click', () => {
dialog.showModal();
});
dialog.addEventListener('click', (event) => {
if (event.target.value === 'ok') {
console.log('delete');
}
dialog.close();
});showModal() 会自动处理焦点、ESC 关闭、背景遮罩这些细节。
三、滚动与尺寸监听
5. IntersectionObserver:懒加载和曝光埋点
用 scroll 事件做懒加载容易写出性能问题。元素进出视口,优先用 IntersectionObserver:
const observer = new IntersectionObserver((entries) => {
for (const entry of entries) {
if (!entry.isIntersecting) continue;
const img = entry.target;
img.src = img.dataset.src;
observer.unobserve(img);
}
});
document.querySelectorAll('img[>).forEach((img) => {
observer.observe(img);
});曝光埋点也是同一个思路:元素第一次进入视口时上报,然后 unobserve。
6. ResizeObserver:监听元素尺寸,不盯着 window
响应式组件里经常需要知道容器宽度,而不是窗口宽度:
const box = document.querySelector('.chart');
const observer = new ResizeObserver(([entry]) => {
const width = entry.contentRect.width;
box.dataset.size = width > 600 ? 'wide' : 'narrow';
});
observer.observe(box);图表、虚拟列表、卡片布局都能用它。卸载组件时记得 observer.disconnect()。
四、通信与同步
7. BroadcastChannel:多标签页通信
一个标签页退出登录,其他标签页也要同步退出,不用轮询 localStorage:
const channel = new BroadcastChannel('auth');
logoutButton.addEventListener('click', () => {
channel.postMessage({ type: 'logout' });
});
channel.addEventListener('message', (event) => {
if (event.data.type === 'logout') {
location.href = '/login';
}
});同源页面都能收到消息。后台管理系统、多标签工作台很常用。
8. Web Locks:避免多标签重复执行任务
有些任务只应该跑一次,比如刷新 token、同步离线队列:
async function syncOnce() {
if (!navigator.locks) return;
await navigator.locks.request('sync-queue', async () => {
console.log('only one tab runs this');
await sendPendingRequests();
});
}它的核心价值是解决“用户开了 5 个标签页,5 个页面同时干同一件事”的问题。Web Locks API 自 2022 年 3 月起已在各浏览器中可用。
9. StorageEvent:localStorage 跨标签同步
如果只是同步一个简单状态,storage 事件够用了:
window.addEventListener('storage', (event) => {
if (event.key === 'theme') {
document.documentElement.dataset.theme = event.newValue;
}
});
function setTheme(theme) {
localStorage.setItem('theme', theme);
document.documentElement.dataset.theme = theme;
}注意一点:修改 localStorage 的当前页面不会收到自己的 storage 事件,所以本页状态要自己更新。
五、文件处理
10. URL.createObjectURL:更轻的文件预览
预览图片、视频、PDF 时,createObjectURL 比 FileReader 更直接,性能也更好:
fileInput.addEventListener('change', () => {
const file = fileInput.files[0];
if (!file) return;
const url = URL.createObjectURL(file);
preview.src = url;
preview.onload = () => {
URL.revokeObjectURL(url);
};
});关键点是用完释放,别让对象 URL 一直挂着。大文件预览优先用这个,别一股脑读成 base64 字符串。
11. structuredClone:深拷贝别再 JSON 转一圈
JSON.parse(JSON.stringify(obj)) 会丢 Date、Map、Set、undefined,还处理不了循环引用:
const source = {
createdAt: new Date(),
tags: new Set(['browser', 'api']),
};
const copy = structuredClone(source);
console.log(copy.createdAt instanceof Date); // true
console.log(copy.tags instanceof Set); // true这个 API 自 2022 年 3 月起可在最新设备和浏览器上运行,普通业务对象深拷贝优先试试它。
六、动效
12. Web Animations API:简单动效不用动画库
按钮反馈、列表进入、提示条消失,这类动效直接用 element.animate():
toast.animate(
[
{ opacity: 0, transform: 'translateY(8px)' },
{ opacity: 1, transform: 'translateY(0)' },
],
{
duration: 180,
easing: 'ease-out',
fill: 'both',
}
);它返回的是 Animation 对象,可以暂停、反放、等待结束:
const animation = panel.animate(keyframes, options);
await animation.finished;
panel.remove();13. View Transitions API:页面状态切换更顺
列表切详情、主题切换、局部视图切换,很多时候不需要上复杂动画方案:
function switchTheme(theme) {
const update = () => {
document.documentElement.dataset.theme = theme;
};
if (!document.startViewTransition) {
update();
return;
}
document.startViewTransition(update);
}再配一点 CSS:
::view-transition-old(root),
::view-transition-new(root) {
animation-duration: 220ms;
}这个 API 的浏览器支持在过去一年进步很大。单文档 View Transitions 目前 Chrome/Edge 111+、Safari 18+、Firefox 144+ 都已支持。适合做体验增强,不要把核心功能绑死在它上面。
七、其他常用能力
14. PerformanceObserver:采样页面性能
想看 LCP、资源加载、长任务,不用马上接监控 SDK:
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log(entry.entryType, entry.name, entry.startTime);
}
});
observer.observe({
entryTypes: ['largest-contentful-paint', 'resource', 'longtask'],
});15. online/offline:离线提示不用猜
function updateNetworkStatus() {
document.body.dataset.online = String(navigator.onLine);
}
window.addEventListener('online', updateNetworkStatus);
window.addEventListener('offline', updateNetworkStatus);
updateNetworkStatus();navigator.onLine 不是万能网络诊断,只能做轻量提示。真正的请求仍然要处理失败和重试。
16. CompressionStream:浏览器里压缩数据
要把日志、配置压成 gzip,不一定非得引入压缩库:
async function gzipText(text) {
const stream = new Blob([text])
.stream()
.pipeThrough(new CompressionStream('gzip'));
return await new Response(stream).blob();
}
const file = await gzipText(JSON.stringify({ hello: 'browser' }));
console.log(file.size);这个 API 对 Chromium 系浏览器支持较好,上线前先看你的用户浏览器分布。
17. File System Access API:直接读写本地文件
做 Markdown 编辑器、图片处理工具时,它能让 Web 应用更像桌面软件:
async function openTextFile() {
const [handle] = await window.showOpenFilePicker({
types: [
{
description: 'Text',
accept: { 'text/plain': ['.txt', '.md'] },
},
],
});
const file = await handle.getFile();
return await file.text();
}保存文件:
async function saveText(text) {
const handle = await window.showSaveFilePicker({
suggestedName: 'note.md',
});
const writable = await handle.createWritable();
await writable.write(text);
await writable.close();
}注意这个 API 的兼容性限制很大。目前只有 Chromium 系浏览器(Chrome 105+、Edge 105+)在 Windows、macOS、ChromeOS、Linux 和 Android 上支持,Safari 和 Firefox 完全不支持。适合工具型产品做渐进增强,不能作为核心依赖。
18. EyeDropper:浏览器里直接取色
做低代码、设计工具、主题配置时很好用:
async function pickColor() {
if (!('EyeDropper' in window)) return;
const eyeDropper = new EyeDropper();
const result = await eyeDropper.open();
console.log(result.sRGBHex);
}兼容性不算完整,适合做增强能力:支持就展示取色按钮,不支持就让用户手动输入色值。
19. MutationObserver:监听 DOM 变化
接入第三方脚本、富文本编辑器时,DOM 变化不一定经过你的框架状态:
const target = document.querySelector('#editor');
const observer = new MutationObserver((mutations) => {
console.log('changed', mutations.length);
});
observer.observe(target, {
childList: true,
subtree: true,
characterData: true,
});别拿它替代 React/Vue 状态管理。它更适合处理“外部代码改了 DOM,我需要知道”的场景。
20. FileReader:本地文件预览
头像上传前预览、导入 JSON 配置:
fileInput.addEventListener('change', () => {
const file = fileInput.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = () => {
preview.src = reader.result;
};
reader.readAsDataURL(file);
});大文件不建议一股脑读成字符串,要考虑流式处理或分片。如果是图片预览,用上面的 URL.createObjectURL 更合适。
速查表
| 场景 | 原生能力 |
|---|---|
| 复制文本 | Clipboard API |
| 系统分享 | Web Share API |
| 弹出菜单 | Popover API |
| 模态确认框 | Dialog |
| 页面取色 | EyeDropper |
| 懒加载 / 曝光 | IntersectionObserver |
| 容器尺寸变化 | ResizeObserver |
| DOM 外部变化 | MutationObserver |
| 性能采样 | PerformanceObserver |
| 多标签通信 | BroadcastChannel |
| 多标签互斥任务 | Web Locks |
| 离线提示 | online / offline |
| localStorage 同步 | StorageEvent |
| 文件读取 | FileReader |
| 文件预览 | URL.createObjectURL |
| 深拷贝 | structuredClone |
| gzip 压缩 | CompressionStream |
| 本地文件读写 | File System Access API |
| 基础动效 | Web Animations API |
| 页面切换动效 | View Transitions API |
什么时候该用,什么时候不该用
不是说所有库都不该装。日期处理、复杂拖拽、富文本编辑器、虚拟列表、图表这些领域,成熟库依然更省心,自己写反而容易踩坑。
但边界清晰的小需求,先查一下浏览器有没有原生能力,往往能少引一个依赖、少维护一层封装,也少一份供应链风险。对前端项目来说,包体积只是表面上的收益,真正省下来的是长期维护成本。
你项目里最想用原生 API 替代掉哪个 npm 包?
本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!