InactivityTimer.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. export class InactivityTimer {
  2. constructor(options = {}) {
  3. this.defaults = {
  4. timeout: 30000, // 默认30秒超时
  5. warningTime: 5000, // 提前5秒警告
  6. onTimeout: () => console.log('Timeout callback'),
  7. onWarning: () => console.log('Warning callback'),
  8. onReset: () => {},
  9. onStart: () => {},
  10. onStop: () => {}
  11. };
  12. this.config = { ...this.defaults, ...options };
  13. this.timer = null;
  14. this.timeLeft = this.config.timeout;
  15. this.isRunning = false;
  16. this.isPaused = false;
  17. this.warningTriggered = false;
  18. this.startTime = null;
  19. this.pageVisible = true;
  20. this.init();
  21. }
  22. init() {
  23. document.addEventListener('visibilitychange', () => this.handleVisibilityChange());
  24. this.setupActivityListeners();
  25. }
  26. setupActivityListeners() {
  27. ['mousemove', 'keydown', 'click', 'scroll', 'touchstart'].forEach(event => {
  28. document.addEventListener(event, () => this.handleUserActivity());
  29. });
  30. }
  31. handleUserActivity() {
  32. if (this.isRunning && !this.isPaused) {
  33. this.resetTimer();
  34. }
  35. }
  36. handleVisibilityChange() {
  37. this.pageVisible = document.visibilityState === 'visible';
  38. if (this.pageVisible && this.isRunning && this.isPaused) {
  39. this.isPaused = false;
  40. this.startTime = Date.now() - (this.config.timeout - this.timeLeft);
  41. this.startTimer();
  42. } else if (!this.pageVisible && this.isRunning && !this.isPaused) {
  43. this.isPaused = true;
  44. this.clearTimer();
  45. }
  46. }
  47. start() {
  48. if (this.isRunning) return;
  49. this.isRunning = true;
  50. this.isPaused = false;
  51. this.warningTriggered = false;
  52. this.startTime = Date.now();
  53. this.timeLeft = this.config.timeout;
  54. this.config.onStart();
  55. this.startTimer();
  56. }
  57. startTimer() {
  58. this.clearTimer();
  59. this.timer = setInterval(() => {
  60. if (!this.isPaused) {
  61. const elapsed = Date.now() - this.startTime;
  62. this.timeLeft = this.config.timeout - elapsed;
  63. if (this.timeLeft <= 0) {
  64. this.clearTimer();
  65. this.isRunning = false;
  66. this.timeLeft = 0;
  67. this.config.onTimeout();
  68. } else if (this.timeLeft <= this.config.warningTime && !this.warningTriggered) {
  69. this.warningTriggered = true;
  70. this.config.onWarning();
  71. }
  72. }
  73. }, 100);
  74. }
  75. resetTimer() {
  76. this.startTime = Date.now();
  77. this.timeLeft = this.config.timeout;
  78. this.warningTriggered = false;
  79. this.config.onReset();
  80. }
  81. reset() {
  82. if (!this.isRunning) return;
  83. this.resetTimer();
  84. }
  85. stop() {
  86. if (!this.isRunning) return;
  87. this.clearTimer();
  88. this.isRunning = false;
  89. this.isPaused = false;
  90. this.timeLeft = this.config.timeout;
  91. this.warningTriggered = false;
  92. this.config.onStop();
  93. }
  94. clearTimer() {
  95. if (this.timer) {
  96. clearInterval(this.timer);
  97. this.timer = null;
  98. }
  99. }
  100. }