You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Chrome扩展:如何监听YouTube滚动加载事件以重新标记视频

Hey there! Let's sort out that infinite scroll issue for your YouTube tagging extension—this is a super common problem with dynamic content sites like YouTube, so I’ve got a couple of proven solutions for you.

The Best Approach: Use MutationObserver

YouTube loads new videos by dynamically inserting elements into the DOM, so the most reliable way to catch these new videos is to listen for changes to the page's DOM using MutationObserver. This is the standard, high-performance method for tracking dynamic content updates.

Here's how to implement it:

Step 1: Refine Your Tagging Function

First, update your existing tagging function to handle both initial and new videos efficiently, adding a marker to avoid redundant API calls:

function markVideos(videoElements) {
  videoElements.forEach(video => {
    // Skip if video was already processed
    if (video.dataset.tagged) return;
    
    // Extract video ID (adjust selector if YouTube's DOM shifts)
    const videoLink = video.querySelector('#video-title-link');
    const videoId = videoLink.href.split('v=')[1].split('&')[0];
    
    // Call YouTube Data API to fetch category (critical: move this to background script for API key security!)
    fetch(`https://www.googleapis.com/youtube/v3/videos?id=${videoId}&part=snippet&key=YOUR_API_KEY`)
      .then(res => res.json())
      .then(data => {
        const categoryId = data.items[0].snippet.categoryId;
        // Map category ID to your color scheme
        if (categoryId === '27') { // Education category ID
          video.style.backgroundColor = '#e8f0fe';
        }
        // Mark as processed to prevent re-runs
        video.dataset.tagged = 'true';
      });
  });
}

Step 2: Set Up the Mutation Observer

This will watch the YouTube video container for new elements being added:

// Run initial tagging when DOM is ready
document.addEventListener('DOMContentLoaded', () => {
  const initialVideos = document.querySelectorAll('ytd-video-renderer');
  markVideos(initialVideos);

  // Target the container where YouTube inserts new videos (adjust if needed)
  const videoContainer = document.querySelector('ytd-item-section-renderer #contents') || document.querySelector('#contents');
  if (!videoContainer) return;

  // Create observer instance
  const observer = new MutationObserver((mutations) => {
    mutations.forEach(mutation => {
      // Filter only new video renderer elements
      const newVideos = Array.from(mutation.addedNodes).filter(node => 
        node.tagName === 'YTD-VIDEO-RENDERER' && node.isConnected
      );
      
      // Tag new videos if any were added
      if (newVideos.length > 0) {
        markVideos(newVideos);
      }
    });
  });

  // Start observing the container for child node changes
  observer.observe(videoContainer, {
    childList: true,
    subtree: true // Needed in case videos are nested in child elements
  });
});

Critical Tips to Avoid Issues

  • YouTube DOM Stability: YouTube occasionally updates its DOM structure. If selectors break, inspect the page to find the latest container or video element. ytd-video-renderer is fairly stable, but parent containers might shift.
  • API Key Security: Never hardcode your YouTube Data API key in a content script—anyone can inspect it! Move the API call to your extension's background script, then use chrome.runtime.sendMessage to send the video ID to the background, and chrome.runtime.onMessage.addListener to receive category data back.
  • Manifest Configuration: Ensure your content script runs at the right time by setting run_at: "document_end" in your manifest.json:
"content_scripts": [
  {
    "matches": ["https://www.youtube.com/*"],
    "js": ["content.js"],
    "run_at": "document_end"
  }
]

If MutationObserver doesn’t work for edge cases, use a scroll event with debouncing as a backup. It’s less efficient but functional:

let debounceTimer;
window.addEventListener('scroll', () => {
  clearTimeout(debounceTimer);
  debounceTimer = setTimeout(() => {
    // Find all unprocessed videos
    const unmarkedVideos = document.querySelectorAll('ytd-video-renderer:not([data-tagged])');
    if (unmarkedVideos.length > 0) {
      markVideos(unmarkedVideos);
    }
  }, 300); // Wait 300ms after last scroll to avoid constant checks
});

内容的提问来源于stack exchange,提问作者SagiZiv

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 20:02:29