useIdle() composable 会在用户停止与你的应用交互时告诉你:在给定的一段时间内没有鼠标移动、点击、按键、触摸或滚轮操作。它的典型用途包括:在无人观看时暂停轮询或动画、在会话即将过期、用户被登出之前发出警告,或者让自助终端(kiosk)的屏幕变暗。
它监听 document 上的活动事件,因此无论你的组件渲染在哪里,它都能覆盖整个页面。
在 SSR 或 SSG 模式的服务端,该 composable 不会追踪任何东西,isIdle 始终保持为 false。
该 composable 也可以在 setup() 之外调用:在 boot 文件、store 或普通模块中。此时它会立即开始追踪,并且不会自行停止:完成后请调用 stopIdle()。
语法
import { useIdle } from 'quasar'
setup () {
const { isIdle, lastActive, resetIdle, stopIdle } = useIdle({
// all optional:
timeout: 60000, // ms of inactivity before the user counts as idle
events: [ // the events (on document) that count as an activity
'mousemove', 'mousedown', 'keydown', 'touchstart', 'wheel'
],
disabled: false, // pause tracking
onIdle (isIdle) { // called on every transition
// ...
}
})
// ...
}function useIdle(
options?: MaybeRefOrGetter<{
timeout?: number
events?: string[]
disabled?: boolean
onIdle?: (isIdle: boolean) => void
}>
): {
isIdle: Ref<boolean>
lastActive: Ref<number>
resetIdle: () => void
stopIdle: () => void
}一旦 timeout 毫秒内没有任何 events 触发,isIdle 就会变为 true,而在紧接着的下一次活动时又回到 false。每一次这样的状态切换都会以新的值调用 onIdle 回调(初始的活动状态不会触发),因此你无需自己去 watch 这个 ref。lastActive 保存了最后一次活动的时间戳(相当于 Date.now() 得到的值),你可以用它来展示「离开时长」,或计算距离用户进入空闲状态还剩多少时间。
这些活动事件是在捕获阶段(capture phase)监听的,因此即便某个处理函数阻止了事件传播,活动依然会被计入;并且这些监听器是被动(passive)的,绝不会拖慢滚动。一次活动本身开销很小:只是记录一个时间戳,别无其他。内部计时器每个周期只装填(arm)一次,触发时才检查已过去的时间,因此连续的 mousemove 事件流并不会反复重置计时器。
页面处于隐藏状态(切到其他标签页、窗口被最小化)时所度过的时间会被计为不活动。浏览器会限制被隐藏页面的计时器,因此该 composable 会在页面重新可见的第一时间把状态确定下来。
resetIdle() 相当于你手动制造了一次活动,用于那些事件无法感知到的交互(例如通过 websocket 收到一条你认为足以维持会话活跃的消息,或者一段仍在播放的视频)。stopIdle() 会彻底结束追踪;你很少会用到它,因为组件销毁时该 composable 会自行停止。
运行时更改选项
选项可以是一个普通对象、一个 Ref 或一个 getter 函数。普通对象只读取一次。使用 Ref 或 getter 时,该 composable 会追踪它所读取的任何响应式状态,并在该状态变化时重新应用:
- 切换
disabled会暂停追踪(被暂停的用户永远不会进入空闲),重新启用时会从那一刻起开始一个全新的计时周期 - 更改
timeout会立即重新评估状态:更短的值可能会让用户当场进入空闲,更长的值可能会让他们重新变为活动 - 更改
events会替换掉相应的监听器
import { ref } from 'vue'
import { useIdle } from 'quasar'
setup () {
const loggedIn = ref(false)
const { isIdle } = useIdle(() => ({
timeout: 5 * 60 * 1000,
disabled: !loggedIn.value
}))
// ...
}示例
下面这个示例演示了 useIdle() 的基本用法:停止移动鼠标、打字或触摸页面 5 秒后,状态就会从 active 变为 idle,你还可以切换开关来暂停追踪。
<template>
<div class="q-pa-md">
<div class="row items-center q-gutter-sm q-mb-md">
<q-btn color="primary" label="resetIdle()" no-caps @click="resetIdle" />
<q-toggle v-model="disabled" label="Disable tracking" />
</div>
<div class="row items-center q-gutter-sm">
<q-badge
:color="isIdle ? 'orange' : 'positive'"
:label="isIdle ? 'idle' : 'active'"
/>
<div v-if="elapsed !== null">Last activity: {{ elapsed }}s ago</div>
</div>
<div class="text-caption q-mt-sm">
Stop moving the mouse, typing or touching the page for 5 seconds.
</div>
</div>
</template>
<script setup>
import { onMounted, ref } from 'vue'
import { useIdle, useInterval } from 'quasar'
const disabled = ref(false)
const { isIdle, lastActive, resetIdle } = useIdle(() => ({
timeout: 5000,
disabled: disabled.value
}))
const elapsed = ref(null)
const { registerInterval } = useInterval()
onMounted(() => {
registerInterval(() => {
elapsed.value = Math.round((Date.now() - lastActive.value) / 1000)
}, 1000)
})
</script>在会话即将过期时向用户发出警告,而这个警告会在用户重新交互的一瞬间自动消失:
import { ref } from 'vue'
import { useIdle } from 'quasar'
setup () {
const showWarning = ref(false)
useIdle({
timeout: 10 * 60 * 1000,
onIdle (isIdle) {
showWarning.value = isIdle
}
})
// ...
}如果你想仅仅对页面本身的隐藏或显示做出反应(而不关心用户是否在活动),请使用 AppVisibility 插件。