前端开发必知:5个浏览器原生API,比你自己封装的更好用
前端开发里有很多“重复造轮子”的操作:自己封装复制到剪贴板、手写页面可见性监听、用定时器轮询网络状态……
其实浏览器早就内置了这些API,很多人只是不知道。今天整理5个,每一个都是“知道了就再也回不去”的那种。
1. Clipboard API:一行代码实现复制
以前你是不是这样写复制功能的?
// 老写法:繁琐又 hack
function copyText(text) {
const input = document.createElement('input');
input.value = text;
document.body.appendChild(input);
input.select();
document.execCommand('copy');
document.body.removeChild(input);
}现在只需要:
// 现代写法
async function copyText(text) {
await navigator.clipboard.writeText(text);
console.log('复制成功!');
}读取剪贴板内容:
async function pasteText() {
const text = await navigator.clipboard.readText();
console.log('剪贴板内容:', text);
}完整的一键复制按钮示例:
const btn = document.querySelector('#copy-btn');
const code = document.querySelector('#code-block').textContent;
btn.addEventListener('click', async () => {
try {
await navigator.clipboard.writeText(code);
btn.textContent = '已复制';
setTimeout(() => btn.textContent = '复制代码', 1500);
} catch (err) {
console.error('复制失败:', err);
}
});兼容性:Chrome 66+、Firefox 63+、Safari 13.1+。注意需要HTTPS或localhost环境,否则API不可用。
2. Page Visibility API:页面隐藏时暂停操作
用户切换到其他标签页时,你的视频还在播放、定时器还在跑、请求还在发——这不仅浪费资源,体验也不好。
Page Visibility API让你精确感知页面是否可见:
// 监听页面可见性变化
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
// 页面隐藏:暂停播放、停止轮询
video.pause();
clearInterval(pollingTimer);
console.log('页面隐藏,已暂停');
} else {
// 页面重新可见:恢复播放、重启轮询
video.play();
pollingTimer = startPolling();
console.log('页面可见,已恢复');
}
});实际场景:自动暂停轮播图
let autoplay;
function startAutoplay() {
autoplay = setInterval(() => nextSlide(), 3000);
}
function stopAutoplay() {
clearInterval(autoplay);
}
// 切换标签页时自动暂停/恢复
document.addEventListener('visibilitychange', () => {
document.hidden ? stopAutoplay() : startAutoplay();
});
startAutoplay();查看当前可见状态:
console.log(document.visibilityState);
// 'visible' - 页面可见
// 'hidden' - 页面隐藏(切换标签、最小化)
// 'prerender'- 页面正在预渲染(不常见)兼容性:Chrome 33+、Firefox 18+、Safari 7+,放心用。
3. Network Information API:感知网络质量
你有没有想过,在弱网环境下自动切换低清图片、跳过自动播放视频?Network Information API就是干这个的:
const connection = navigator.connection
|| navigator.mozConnection
|| navigator.webkitConnection;
if (connection) {
console.log('网络类型:', connection.effectiveType);
// '4g' | '3g' | '2g' | 'slow-2g'
console.log('下行速度:', connection.downlink, 'Mbps');
console.log('往返延迟:', connection.rtt, 'ms');
console.log('节省数据模式:', connection.saveData);
}根据网络质量动态加载图片:
function getImageSrc(highRes, lowRes) {
const connection = navigator.connection;
// 弱网或开启数据节省模式,用低清图
if (connection) {
const isSlowNetwork = ['slow-2g', '2g', '3g'].includes(connection.effectiveType);
if (isSlowNetwork || connection.saveData) {
return lowRes;
}
}
return highRes;
}
// 使用
img.src = getImageSrc('photo-4k.jpg', 'photo-thumb.jpg');监听网络变化:
navigator.connection?.addEventListener('change', () => {
const type = navigator.connection.effectiveType;
if (type === '4g') {
loadHighQualityContent();
} else {
loadLightContent();
}
});兼容性:Chrome 61+、Android WebView 50+。Firefox和Safari支持有限,使用时建议做if (navigator.connection)判断。
4. matchMedia():JS里监听媒体查询变化
响应式设计不只是CSS的事,有时候JS也需要知道当前是手机还是桌面——比如动态加载不同的组件、切换交互方式。
很多人会用window.innerWidth轮询,其实有更好的方式:
// 不推荐:窗口resize时每次都计算
window.addEventListener('resize', () => {
if (window.innerWidth < 768) {
// 移动端逻辑
}
});
// 推荐:直接监听媒体查询
const mql = window.matchMedia('(max-width: 768px)');
// 初始状态
console.log('是否移动端:', mql.matches);
// 监听变化(窗口大小改变时触发)
mql.addEventListener('change', (e) => {
if (e.matches) {
console.log('切换到移动端');
loadMobileComponent();
} else {
console.log('切换到桌面端');
loadDesktopComponent();
}
});监听深色模式切换:
const darkMode = window.matchMedia('(prefers-color-scheme: dark)');
// 当前模式
console.log('深色模式:', darkMode.matches);
// 用户切换系统主题时触发
darkMode.addEventListener('change', (e) => {
document.body.classList.toggle('dark', e.matches);
});封装成工具函数:
function onMediaChange(query, callback) {
const mql = window.matchMedia(query);
callback(mql.matches); // 立即执行一次
mql.addEventListener('change', (e) => callback(e.matches));
return () => mql.removeEventListener('change', callback); // 返回清理函数
}
// 使用
const cleanup = onMediaChange('(max-width: 768px)', (isMobile) => {
console.log('isMobile:', isMobile);
});
// 组件卸载时清理
// cleanup();兼容性:Chrome 9+、Firefox 6+、Safari 5.1+,全面兼容,放心用。
5. requestIdleCallback():利用空闲时间做低优先级任务
你需要在页面加载后做一些不紧急的工作——埋点上报、预加载、缓存更新——但不想影响用户交互的流畅度。
requestIdleCallback专门解决这个问题:浏览器在每帧空闲时调用你的回调,不抢占用户交互所需的时间:
// 用setTimeout凑合:不知道什么时候浏览器有空
setTimeout(() => {
sendAnalytics();
}, 0);
// 推荐:浏览器空闲时再执行
requestIdleCallback((deadline) => {
// deadline.timeRemaining() 返回当前帧剩余空闲毫秒数
console.log('空闲时间:', deadline.timeRemaining(), 'ms');
sendAnalytics();
preloadNextPage();
});处理任务队列,超时兜底:
const tasks = [
() => sendAnalytics(),
() => preloadImages(),
() => updateLocalCache(),
];
function runTasksInIdle(tasks) {
let index = 0;
function runNext(deadline) {
// 当还有空闲时间 且 还有任务时,继续执行
while (deadline.timeRemaining() > 1 && index < tasks.length) {
tasks[index++]();
}
// 还有剩余任务,下一次空闲继续
if (index < tasks.length) {
requestIdleCallback(runNext);
}
}
// timeout: 最迟2000ms内必须执行(兜底)
requestIdleCallback(runNext, { timeout: 2000 });
}
runTasksInIdle(tasks);兼容性:Chrome 47+、Firefox 55+。Safari不支持,降级方案:
const rIC = window.requestIdleCallback || ((cb) => setTimeout(cb, 1));总结
| API | 用途 | 替代什么 | 最低兼容 |
|---|---|---|---|
| Clipboard API | 读写剪贴板 | execCommand('copy') hack | Chrome 66+ |
| Page Visibility API | 感知页面是否可见 | 定时器轮询 | Chrome 33+ |
| Network Information API | 感知网络类型/速度 | 无(以前做不到) | Chrome 61+ |
| matchMedia() | JS里监听媒体查询 | resize事件 + innerWidth | Chrome 9+ |
| requestIdleCallback() | 空闲时执行低优先级任务 | setTimeout(fn, 0) | Chrome 47+ |
这5个API都是浏览器多年前就支持的成熟特性,不需要任何依赖,不用npm install,直接用就行。
本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!