前端开发必知:5个浏览器原生API,比你自己封装的更好用

摘要:前端开发里有很多“重复造轮子”的操作:自己封装复制到剪贴板、手写页面可见性监听、用定时器轮询网络状态……其实浏览器早就内置了这些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') hackChrome 66+
Page Visibility API感知页面是否可见定时器轮询Chrome 33+
Network Information API感知网络类型/速度无(以前做不到)Chrome 61+
matchMedia()JS里监听媒体查询resize事件 + innerWidthChrome 9+
requestIdleCallback()空闲时执行低优先级任务setTimeout(fn, 0)Chrome 47+

这5个API都是浏览器多年前就支持的成熟特性,不需要任何依赖,不用npm install,直接用就行。

本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!

链接: https://shenqiku.cn/article/FLY_13571