# Idle Detection API：检测用户与屏幕的空闲状态

> IdleDetector 接口如何报告用户是活跃还是空闲、屏幕是锁定还是解锁，它的权限模型与 60 秒最小阈值，以及它在哪些浏览器中已经（或尚未）实现。

**一句话：** Idle Detection API 的 `IdleDetector` 接口让页面能够查询用户在给定阈值内是
否与屏幕或设备发生过交互，以及屏幕当前是否锁定，并在任一状态发生变化时触发 `change`
事件。

## 请求权限

根据 MDN，启动 `IdleDetector` 需要 `idle-detection` 权限，且
`IdleDetector.requestPermission()` 需要瞬态用户激活——必须在用户手势（例如点击处理器）
内部调用：

```js
startButton.addEventListener('click', async () => {
  const permission = await IdleDetector.requestPermission();
  if (permission !== 'granted') {
    console.error('Idle detection permission denied.');
    return;
  }
  await startIdleDetector();
});
```

## 启动检测器

`start()` 接收一个以毫秒为单位的 `threshold` 及一个可选的 `AbortSignal`。根据 WICG
规范，当 `threshold` 低于 60,000ms（60 秒）时，`start()` 会以 `TypeError` 拒绝——
没有办法要求更细粒度的报告：

```js
async function startIdleDetector() {
  const controller = new AbortController();
  const idleDetector = new IdleDetector();

  idleDetector.addEventListener('change', () => {
    console.log(`User: ${idleDetector.userState}, Screen: ${idleDetector.screenState}`);
  });

  await idleDetector.start({
    threshold: 60_000,
    signal: controller.signal,
  });
}
```

`userState` 报告 `"active"` 或 `"idle"`；`screenState` 报告 `"locked"` 或 `"unlocked"`。
根据 MDN，两者在调用 `start()` 之前都返回 `null`，`start()` 会为它们赋予初始值。

## 支持情况

根据 MDN 的兼容性数据，`IdleDetector` 仅在基于 Chromium 的浏览器中提供（自 Chrome
94 版起），且需要安全上下文。Firefox 和 Safari 均未实现它。

## 特性检测与回退

```js
async function watchIdleState(onChange) {
  if (!('IdleDetector' in window)) {
    // 不受支持：这里没有这个 API 所暴露的操作系统级空闲/锁定状态可报告，
    // 因此直接报告 unknown，而不是去猜测。
    onChange({ userState: 'unknown', screenState: 'unknown' });
    return;
  }

  const permission = await IdleDetector.requestPermission();
  if (permission !== 'granted') {
    onChange({ userState: 'unknown', screenState: 'unknown' });
    return;
  }

  const idleDetector = new IdleDetector();
  idleDetector.addEventListener('change', () => {
    onChange({ userState: idleDetector.userState, screenState: idleDetector.screenState });
  });
  await idleDetector.start({ threshold: 60_000 });
}
```

## 实用清单

- [ ] 在引用该类之前先用 `'IdleDetector' in window` 做特性检测——它在 Firefox 和
      Safari 中并不存在。
- [ ] 在用户手势内部调用 `IdleDetector.requestPermission()`；没有瞬态用户激活的调用
      按规范会失败。
- [ ] 不要把 `threshold` 设置为低于 60,000ms——`start()` 会以 `TypeError` 拒绝，
      而不仅仅是报告得更慢。
- [ ] 在调用 `start()` 之前，将 `userState` 和 `screenState` 视为 `null`；不要在
      构造之后立即同步读取它们。
- [ ] 为目前尚未实现该 API 的 Firefox 和 Safari 提供可用的回退体验，而不是静默降级。

## 相关参考

- [Screen Wake Lock API](/zh/reference/capabilities/wake-lock/) —— 另一个与设备
  状态相关的能力 API。
- [Firefox 上的 PWA](/zh/reference/platforms/firefox/) —— 更多关于
  Firefox 平台能力支持的说明。