That's actually a very good question!
Your approach for tracking certain activity events is clever, but in the end it really depends on your definition of "inactivity". If your are happy with your current definition, then you can probably track a few more like scroll or resize.
另一个"不活动"定义可以是"只要标签是活动的,用户就是活动的".在现代浏览器中,这可以通过文档中的Page Visibility API AKE LISTEN来跟踪visibilitychange
事件.在窗口对象上使用窗口焦点和模糊事件也应该是一种解决方法.
现在,谈到实现本身,我将建议一种简化的方法.
const browserInactive$ = (graceTime: number): Observable<Event> => {
const activityIndicatorEvents = ['click', 'mousemove', 'mousedown', 'scroll', 'keypress'];
return merge(...activityIndicatorEvents.map(eventName => fromEvent(document, eventName))).pipe(debounceTime(graceTime));
};
我自己还没有测试过这一点,但 idea 很简单.它遵循您最初的实现,但我们使用debounceTime
作为等待graceTime"到期"的机制,并使用函数作为配置行为的方便方法.
编辑1:
我有了一个 idea ,可以让您的Angular 组件或服务更容易地使用可观察对象
export const BROWSER_INACTIVE$ = new InjectionToken<Observable<Event>>('Browser inactivity detector', {
factory: () => {
const activityIndicatorEvents = ['click', 'mousemove', 'mousedown', 'scroll', 'keypress'];
const graceTime = 1000 * 60 * 5; // 5 minutes
return merge(...activityIndicatorEvents.map(eventName => fromEvent(document, eventName))).pipe(debounceTime(graceTime), share());
}
});
然后可以像这样使用它:
@Component({...})
export class SomeComponent {
constructor(
@Inject(BROWSER_INACTIVE$) private readonly browserInactive$: Observable<Event>
) {}
}
编辑2:基于业务反馈.
在这种情况下,我们可以使用稍微不同的方法:
const browserInactive$ = (graceTime: number): Observable<any> => {
const activityIndicatorEvents$ = merge(
...['click', 'mousemove', 'mousedown', 'scroll', 'keypress'].map(
(eventName) => fromEvent(document, eventName)
)
);
return interval(graceTime).pipe(
takeUntil(activityIndicatorEvents$),
repeat()
);
};
现在的 idea 是,我们有某种类型的timer(实际上是interval
),它将每gracePeriod
次emits 一次,除非检测到activityIndicator事件.问题是takeUntil
将完成流,因此我们需要使用repeat
来使其保持活动状态:)