阿里云主机折上折
  • 微信号
Current Site:Index > Web page title blinking: setInterval(() => document.title = document.title === 'Slacking off' ? '🐟' : 'Slacking off', 500);

Web page title blinking: setInterval(() => document.title = document.title === 'Slacking off' ? '🐟' : 'Slacking off', 500);

Author:Chuan Chen 阅读数:13090人阅读 分类: JavaScript

Flashing Web Page Title: setInterval(() => document.title = document.title === 'Slacking Off' ? '🐟' : 'Slacking Off', 500);

A flashing web page title is a common dynamic effect that can be easily achieved using JavaScript's setInterval function. This code switches the document title between "Slacking Off" and "🐟" at 500-millisecond intervals, creating a visual flashing effect.

Implementation Principle Analysis

The core of this code is the combination of the setInterval function and a ternary operator:

setInterval(() => {
  document.title = document.title === 'Slacking Off' ? '🐟' : 'Slacking Off';
}, 500);

setInterval takes two parameters: a callback function and a time interval (in milliseconds). Here, the interval is set to 500 milliseconds, meaning the callback function executes every half second.

The callback function uses a ternary operator to check the current title:

  • If the current title is "Slacking Off," it changes to "🐟"
  • If not (i.e., it's already "🐟"), it reverts to "Slacking Off"

Extended Application Scenarios

This technique can be applied to various scenarios:

  1. Notification Alerts: Flash the title when new messages arrive
let originalTitle = document.title;
let hasNewMessage = false;

function toggleNotification() {
  document.title = hasNewMessage ? 
    '【New Message】' + originalTitle : 
    originalTitle;
  hasNewMessage = !hasNewMessage;
}

const notificationInterval = setInterval(toggleNotification, 1000);

// When a new message is received
function onNewMessage() {
  hasNewMessage = true;
  clearInterval(notificationInterval);
  notificationInterval = setInterval(toggleNotification, 1000);
}
  1. Countdown Effect:
let seconds = 10;
const countdown = setInterval(() => {
  document.title = `Time Left: ${seconds}s`;
  seconds--;
  if(seconds < 0) {
    clearInterval(countdown);
    document.title = "Time's Up!";
  }
}, 1000);

Performance Optimization Considerations

While this effect is cool, performance issues should be noted:

  1. Clearing Timers: Ensure timers are cleared when not needed
let blinkInterval;

function startBlinking() {
  blinkInterval = setInterval(() => {
    document.title = document.title === 'Slacking Off' ? '🐟' : 'Slacking Off';
  }, 500);
}

function stopBlinking() {
  clearInterval(blinkInterval);
  document.title = 'Slacking Off';
}
  1. Using requestAnimationFrame as an Alternative: For smoother animations
let lastTime = 0;
const interval = 500;

function blinkTitle(timestamp) {
  if(timestamp - lastTime > interval) {
    document.title = document.title === 'Slacking Off' ? '🐟' : 'Slacking Off';
    lastTime = timestamp;
  }
  requestAnimationFrame(blinkTitle);
}

requestAnimationFrame(blinkTitle);

Browser Compatibility

While modern browsers support this technique, note:

  1. Mobile Browsers: Some may limit title update frequency
  2. SEO Impact: Frequent title changes may harm search engine optimization
  3. User Experience: Overuse may distract users

Advanced Techniques

  1. Multi-State Flashing:
const states = ['Working', 'Break', 'Coffee Time'];
let index = 0;

setInterval(() => {
  document.title = states[index];
  index = (index + 1) % states.length;
}, 1000);
  1. Random Effects:
const emojis = ['🐟', '🎣', '🏖️', '🛏️', '📱'];
setInterval(() => {
  document.title = emojis[Math.floor(Math.random() * emojis.length)];
}, 300);
  1. Combining with Page Visibility API:
let intervalId;

function handleVisibilityChange() {
  if (document.hidden) {
    intervalId = setInterval(() => {
      document.title = document.title === 'Come Back!' ? 'Page in Background' : 'Come Back!';
    }, 500);
  } else {
    clearInterval(intervalId);
    document.title = 'Welcome Back';
  }
}

document.addEventListener('visibilitychange', handleVisibilityChange);

Practical Application Examples

  1. Chat Applications: When receiving new messages
let isBlinking = false;
let originalTitle = document.title;

socket.on('new-message', () => {
  if(!isBlinking) {
    isBlinking = true;
    const blinkInterval = setInterval(() => {
      document.title = document.title === originalTitle ? 
        'New Message!' : 
        originalTitle;
    }, 800);
    
    // Stop flashing when user returns to the tab
    window.addEventListener('focus', function stopBlink() {
      clearInterval(blinkInterval);
      document.title = originalTitle;
      isBlinking = false;
      window.removeEventListener('focus', stopBlink);
    });
  }
});
  1. Game Applications: When player health is low
let playerHealth = 100;

function updateHealth(change) {
  playerHealth += change;
  
  if(playerHealth < 30 && playerHealth > 0) {
    // Start flashing warning
    if(!window.healthWarningInterval) {
      window.healthWarningInterval = setInterval(() => {
        document.title = document.title.includes('⚠️') ? 
          'Low Health!' : 
          '⚠️ Low Health! ⚠️';
      }, 600);
    }
  } else if(playerHealth <= 0) {
    clearInterval(window.healthWarningInterval);
    document.title = 'Game Over';
  } else {
    clearInterval(window.healthWarningInterval);
    window.healthWarningInterval = null;
    document.title = 'Adventure Game';
  }
}

User Experience Considerations

While title flashing can attract attention, consider:

  1. Flash Frequency: Too fast may cause discomfort; recommend at least 500ms
  2. Duration: Prolonged flashing may annoy; set auto-stop
  3. User Control: Provide options to disable flashing
// Add a stop button on the page
document.getElementById('stopBlink').addEventListener('click', () => {
  clearInterval(blinkInterval);
  document.title = 'Slacking Off';
});
  1. Accessibility: Ensure it doesn't disturb screen reader users

Integration with Other APIs

  1. Combining with Notification API:
// Request notification permission first
Notification.requestPermission().then(permission => {
  if(permission === 'granted') {
    setInterval(() => {
      if(document.hidden) {
        document.title = document.title === 'New Notification' ? 'Please Check' : 'New Notification';
        new Notification('You have a new message', {
          body: 'Please return to the tab',
          icon: '/notification-icon.png'
        });
      }
    }, 10000);
  }
});
  1. Combining with WebSocket:
const socket = new WebSocket('wss://example.com/ws');

socket.onmessage = (event) => {
  const data = JSON.parse(event.data);
  if(data.urgent) {
    let counter = 0;
    const urgentInterval = setInterval(() => {
      document.title = `【Urgent】${data.message.slice(0, 10)}...`;
      if(++counter >= 10) {
        clearInterval(urgentInterval);
        document.title = 'Normal Title';
      }
    }, 500);
  }
};

Debugging Tips

When title flashing doesn't work, debug like this:

  1. Check if Timer is Set Successfully:
const intervalId = setInterval(() => {
  console.log('Executing interval callback'); // Confirm if callback executes
  document.title = document.title === 'Slacking Off' ? '🐟' : 'Slacking Off';
}, 500);

// In console, try clearInterval(intervalId) to stop
  1. Verify Title Modification Permissions:
try {
  document.title = 'Test Title';
  console.log('Title modified successfully');
} catch(e) {
  console.error('Title modification failed:', e);
}
  1. Performance Monitoring:
const start = performance.now();
let count = 0;

const interval = setInterval(() => {
  document.title = `Count: ${++count}`;
  if(count >= 10) {
    clearInterval(interval);
    const duration = performance.now() - start;
    console.log(`10 updates took: ${duration}ms`);
  }
}, 100);

Alternative Solutions

Beyond setInterval, other implementations exist:

  1. Using CSS Animation and MutationObserver:
<style>
  @keyframes titleBlink {
    0%, 100% { content: "Slacking Off"; }
    50% { content: "🐟"; }
  }
</style>

<script>
  const observer = new MutationObserver(() => {
    document.title = getComputedStyle(document.documentElement, '::before')
      .getPropertyValue('content')
      .replace(/["']/g, '');
  });
  
  observer.observe(document.documentElement, {
    attributes: true,
    attributeFilter: ['style']
  });
  
  document.documentElement.style.setProperty('--title-content', '"Slacking Off"');
  document.documentElement.style.animation = 'titleBlink 1s infinite';
</script>
  1. Using Web Worker:
// worker.js
let toggle = false;
setInterval(() => {
  self.postMessage(toggle ? 'Slacking Off' : '🐟');
  toggle = !toggle;
}, 500);

// Main thread
const worker = new Worker('worker.js');
worker.onmessage = (e) => {
  document.title = e.data;
};

Security Considerations

  1. Prevent XSS Attacks: Ensure dynamic title content is escaped
function setSafeTitle(text) {
  const div = document.createElement('div');
  div.textContent = text;
  document.title = div.innerHTML;
}

setInterval(() => {
  setSafeTitle(document.title === 'Safe' ? '<script>alert(1)</script>' : 'Safe');
}, 1000);
  1. Avoid Sensitive Information: Don't expose private data in titles
  2. Permission Control: Some browser extensions may limit title modifications

History and Development

The history of dynamic web title modification dates back to early JavaScript:

  1. Early Implementation: Supported since Netscape Navigator era
  2. Browser Wars: Different browsers had varying frequency limits
  3. Modern Standards: HTML5 specifications clarified title modification behavior

Cross-Platform Behavior Differences

Title flashing behaves differently across environments:

  1. Desktop Browsers: Generally consistent
  2. Mobile Browsers: May be throttled or ignored
  3. PWA Apps: Behavior may differ when running as standalone windows
  4. Electron Apps: Offers more control freedom

Implementation in Frameworks

Implementation in popular frameworks:

  1. React:
import { useEffect, useState } from 'react';

function BlinkingTitle() {
  const [title, setTitle] = useState('Slacking Off');
  
  useEffect(() => {
    const interval = setInterval(() => {
      setTitle(prev => prev === 'Slacking Off' ? '🐟' : 'Slacking Off');
    }, 500);
    
    return () => clearInterval(interval);
  }, []);
  
  useEffect(() => {
    document.title = title;
  }, [title]);
  
  return null;
}
  1. Vue:
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';

const title = ref('Slacking Off');

onMounted(() => {
  const interval = setInterval(() => {
    title.value = title.value === 'Slacking Off' ? '🐟' : 'Slacking Off';
  }, 500);
  
  onUnmounted(() => clearInterval(interval));
});

watch(title, (newVal) => {
  document.title = newVal;
});
</script>
  1. Angular:
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Title } from '@angular/platform-browser';

@Component({
  selector: 'app-blink-title',
  template: ''
})
export class BlinkTitleComponent implements OnInit, OnDestroy {
  private interval: any;
  
  constructor(private titleService: Title) {}
  
  ngOnInit() {
    let isFish = true;
    this.interval = setInterval(() => {
      isFish = !isFish;
      this.titleService.setTitle(isFish ? 'Slacking Off' : '🐟');
    }, 500);
  }
  
  ngOnDestroy() {
    clearInterval(this.interval);
  }
}

Testing Strategies

How to test title flashing functionality:

  1. Unit Testing (using Jest):
// Mock document.title
let mockTitle = '';
Object.defineProperty(document, 'title', {
  get: () => mockTitle,
  set: (value) => { mockTitle = value; }
});

test('Title should alternate', () => {
  jest.useFakeTimers();
  
  const interval = setInterval(() => {
    document.title = document.title === 'Slacking Off' ? '🐟' : 'Slacking Off';
  }, 500);
  
  expect(document.title).toBe('');
  
  jest.advanceTimersByTime(500);
  expect(document.title).toBe('Slacking Off');
  
  jest.advanceTimersByTime(500);
  expect(document.title).toBe('🐟');
  
  jest.advanceTimersByTime(500);
  expect(document.title).toBe('Slacking Off');
  
  clearInterval(interval);
});
  1. E2E Testing (using Cypress):
describe('Title Flashing', () => {
  it('should change every 500ms', () => {
    cy.visit('/');
    cy.title().should('eq', 'Slacking Off');
    
    cy.wait(500);
    cy.title().should('eq', '🐟');
    
    cy.wait(500);
    cy.title().should('eq', 'Slacking Off');
  });
});

Performance Impact Measurement

Measuring the performance impact of title updates:

const iterations = 1000;
let totalTime = 0;

function testTitleUpdate() {
  const start = performance.now();
  
  for(let i = 0; i < iterations; i++) {
    document.title = `Test ${i}`;
  }
  
  const duration = performance.now() - start;
  totalTime += duration;
  console.log(`Completed ${iterations} title updates in: ${duration}ms`);
  
  if(totalTime < 1000) {
    requestAnimationFrame(testTitleUpdate);
  } else {
    console.log(`Average title update time: ${totalTime/iterations}ms`);
  }
}

testTitleUpdate();

Browser Limitations and Countermeasures

Browser-specific limitations on title modifications:

  1. Frequency Limits: Some browsers restrict modification frequency
  2. Background Tabs: Inactive tabs may be throttled
  3. Countermeasures:
let lastUpdate = 0;
const minInterval = 300; // Minimum 300ms interval

function safeTitleUpdate(newTitle) {
  const now = performance.now();
  if(now - lastUpdate >= minInterval) {
    document.title = newTitle;
    lastUpdate = now;
    return true;
  }
  return false;
}

// Usage
setInterval(() => {
  safeTitleUpdate(document.title === 'Slacking Off' ? '🐟' : 'Slacking Off');
}, 100); // Attempt 100ms interval, but will be limited

User Experience Research

Impact of title flashing on user experience:

  1. Attention Grabbing: Effective but potentially excessive
  2. Anxiety: Frequent flashing may cause stress
  3. Best Practices:
    • Use only for important notifications
    • Provide obvious disable options
    • Combine with visual cues (e.g., favicon changes)

Accessibility Improvements

Ensure title flashing doesn't hinder accessibility:

  1. Screen Readers: Frequent changes may interfere
  2. Improved Solution:
let isScreenReader = false;

// Detect screen readers (imperfect but helpful)
if(window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
  isScreenReader = true;
}

function accessibleTitleBlink() {
  if(isScreenReader) {
    document.title = 'New Notification';
    return;
  }
  
  // Normal flashing logic
  setInterval(() => {
    document.title = document.title === 'Slacking Off' ? '🐟' : 'Slacking Off';
  }, 500);
}

Creative Application Examples

Some interesting creative implementations:

  1. Progress Animation:
const frames = ['-', '\\', '|', '/'];
let index = 0;

setInterval(() => {
  document.title = `Processing ${frames[index]}`;
  index = (index + 1) % frames.length;
}, 100);
  1. Typewriter Effect:
const text = "New message incoming...";
let position = 0;
let adding = true;

setInterval(() => {
  if(adding) {
    document.title = text.slice(0, position++);
    if(position > text.length) {
      adding = false;
      setTimeout(() => {}, 1000);
    }
  } else {
    document.title = text.slice(0, position--);
    if(position < 0) {
      adding = true;
    }
  }
}, 100);
  1. Color Code Flashing (partial browser support):
const colors = ['red', 'blue', 'green', 'yellow'];
let colorIndex = 0;

setInterval(() => {
  document.title = `%c${colors[colorIndex]}Title`;
  colorIndex = (colorIndex + 1) % colors.length;
}, 500);

Combining with Other DOM Properties

Not limited to titles; can combine with other properties:

  1. Favicon Flashing:
const canvas = document.createElement('canvas');
canvas.width = 16; canvas.height = 16;
const ctx = canvas.getContext('2d');

let isYellow = false;
setInterval(() => {
  isYellow = !isYellow;
  ctx.fillStyle = isYellow ? 'yellow' : 'red';
  ctx.fillRect(0, 0, 16, 16);
  
  const link = document.querySelector("link[rel*='icon']") || 
    document.createElement('link');
  link.type = 'image/x-icon';

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.