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

YouTube扩展DOM操作首次加载失效,刷新后正常问题求助

YouTube扩展DOM操作首次加载失效问题排查与修复

问题描述

开发YouTube浏览器扩展时,DOM操作功能仅在页面刷新后正常工作,首次加载时无法生效。已尝试调整Manifest中content script的run_at参数,问题仍未解决。

代码片段

Content Script代码(content.js)

import React from "react";
import { createRoot } from "react-dom/client";
import App from "./src/App";
import "./src/index.css";

declare const chrome: any;

if (typeof browser === "undefined") {
  var browser = chrome;
}

class Main extends React.Component {
  render() {
    return (
      <div className={'my-extension'}>
        <App />
      </div>
    )
  }
}

function addReactApp() {

  if(!location.pathname.startsWith('/watch')){
    return;
  }

  const sideBox = document.getElementById("secondary"); 
  const sideBox_inner = document.getElementById("secondary-inner");
  const videoPlayer = document.getElementsByClassName("html5-video-container");

  console.log("videoPlayer",videoPlayer)
  console.log("sideBox_inner",sideBox_inner)
  console.log("sideBox",sideBox)

  if (sideBox && sideBox_inner && videoPlayer) {
    const app = document.createElement("div");
    app.id = "tubechat-ai";

    sideBox.prepend(app);

    const container = document.getElementById("tubechat-ai");
    console.log("container",container)

    if (container) {
      const root = createRoot(container);

      root.render(
        <React.StrictMode>
          <Main />
        </React.StrictMode>
      );
    }
  } else {
    console.log("Not all required elements are present.");
  }
}

document.addEventListener('yt-navigate-finish', addReactApp);

if (document.body) addReactApp();
else document.addEventListener('DOMContentLoaded', addReactApp);

Manifest文件代码(manifest.json)

{
  "manifest_version": 3,
  "name": "Tubechat.ai",
  "version": "1.0.0",
  "permissions": [
    "activeTab",
    "storage",
    "scripting",
    "webNavigation",
    "tabs",
    "notifications"
  ],
  "host_permissions": [
    "http://www.youtube.com/*",
    "https://www.youtube.com/*"
  ],
  "action": {
    "default_popup": "index.html",
    "default_icon": {
      "16": "my-assets/logo.png",
      "48": "my-assets/logo.png",
      "128": "my-assets/logo.png"
    }
  },
  "icons": {
    "16": "my-assets/logo.png",
    "48": "my-assets/logo.png",
    "128": "my-assets/logo.png"
  },
  "content_scripts": [
    {
      "matches": ["*://www.youtube.com/*"],
      "js": ["content.js"],
      "css": ["my-assets/index.css"],
      "run_at": "document_end"
    }
  ],
  "background": {
    "service_worker": "background.js" 
  }
}

问题分析与解决方案

核心问题

YouTube采用单页应用架构,首次加载时yt-navigate-finish事件可能在content script注入前就已触发,导致监听失效;同时document_end时机仍早于目标DOM元素的动态渲染完成时间,加上getElementsByClassName返回空集合时不会触发false判断,导致元素检测逻辑失效。

修复步骤

  1. 修正DOM元素检测逻辑
    getElementsByClassName返回HTMLCollection,空集合不会等于null,需通过长度判断元素是否存在:

    if (sideBox && sideBox_inner && videoPlayer.length > 0) {
      // 后续渲染逻辑
    }
    
  2. 增强页面导航与DOM监听
    使用MutationObserver监听目标元素的动态加载,配合YouTube导航事件确保覆盖所有场景:

    function setupObserver() {
      if(!location.pathname.startsWith('/watch')) return;
    
      const observer = new MutationObserver(() => {
        const sideBox = document.getElementById("secondary");
        const sideBox_inner = document.getElementById("secondary-inner");
        const videoPlayer = document.getElementsByClassName("html5-video-container");
        
        if (sideBox && sideBox_inner && videoPlayer.length > 0) {
          addReactApp();
          observer.disconnect(); // 找到元素后停止监听
        }
      });
    
      observer.observe(document.body, {
        childList: true,
        subtree: true
      });
    }
    
    // 替换原事件监听
    document.addEventListener('yt-navigate-finish', setupObserver);
    document.addEventListener('yt-navigate-start', () => {
      // 导航开始时可重置状态(如已存在则移除旧容器)
      const oldContainer = document.getElementById("tubechat-ai");
      oldContainer?.remove();
    });
    
    if (document.body) setupObserver();
    else document.addEventListener('DOMContentLoaded', setupObserver);
    
  3. 调整Content Script配置
    将run_at设为document_idle确保页面完全加载后注入,同时添加world: "MAIN"保证脚本在主世界执行,能正确监听YouTube自定义事件:

    "content_scripts": [
      {
        "matches": ["*://www.youtube.com/*"],
        "js": ["content.js"],
        "css": ["my-assets/index.css"],
        "run_at": "document_idle",
        "world": "MAIN"
      }
    ]
    
  4. 避免重复渲染
    在addReactApp开头检查容器是否已存在,防止多次创建:

    function addReactApp() {
      if(!location.pathname.startsWith('/watch')) return;
      if (document.getElementById("tubechat-ai")) return;
    
      // 原渲染逻辑
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 18:46:13