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

如何在React应用页面加载完成后执行脚本?含路由切换场景

解决React应用刷新及路由切换时页面加载完成后执行脚本的问题

首先得明确单页应用(SPA)的核心特点:路由切换时页面并没有真正刷新,只是DOM动态更新,所以window.onload、document.onreadystatechange这类页面级加载事件只会在首次刷新时触发,后续路由切换不会再触发——这就是你之前尝试失效的原因。

关于browserHistory的"after钩子":其实browserHistory.listen的回调就是路由切换完成后触发的(它会在location改变、路由跳转完成后执行),但你之前在回调里绑定window.onload是没用的,因为根本没有页面刷新。

下面给你两种场景通用的解决方案,覆盖首次刷新和路由切换两种情况:

方案1:React Router v3(基于browserHistory)

在根组件中结合生命周期和路由监听来实现:

import React from 'react';
import { browserHistory } from 'react-router';

class AppRoot extends React.Component {
  componentDidMount() {
    // 处理首次页面刷新的情况
    this.executeTargetScript();
    
    // 监听路由变化,处理切换场景
    this.unlistenRouter = browserHistory.listen((location) => {
      this.executeTargetScript();
    });
  }

  componentWillUnmount() {
    // 组件卸载时移除路由监听,避免内存泄漏
    this.unlistenRouter();
  }

  executeTargetScript() {
    // 先判断当前页面是否已经处于完全加载状态
    if (document.readyState === 'complete') {
      this.runYourBusinessLogic();
    } else {
      // 若还在加载中,监听状态变化直到完成
      const handleReadyStateChange = () => {
        if (document.readyState === 'complete') {
          document.removeEventListener('readystatechange', handleReadyStateChange);
          this.runYourBusinessLogic();
        }
      };
      document.addEventListener('readystatechange', handleReadyStateChange);
    }
  }

  runYourBusinessLogic() {
    // 这里替换成你要执行的脚本
    // 如果你需要等待当前页面的图片/资源加载完成,可添加下面的检查逻辑
    const allImages = document.querySelectorAll('img');
    const unloadedImgs = Array.from(allImages).filter(img => !img.complete);

    if (unloadedImgs.length === 0) {
      // 所有资源加载完成,执行核心逻辑
      alert("It's loaded!");
    } else {
      // 监听未加载图片的完成事件(包括加载失败的情况,避免无限等待)
      let loadedCount = 0;
      const onImgLoad = () => {
        loadedCount++;
        if (loadedCount === unloadedImgs.length) {
          unloadedImgs.forEach(img => {
            img.removeEventListener('load', onImgLoad);
            img.removeEventListener('error', onImgLoad);
          });
          alert("It's loaded!");
        }
      };
      unloadedImgs.forEach(img => {
        img.addEventListener('load', onImgLoad);
        img.addEventListener('error', onImgLoad);
      });
    }
  }

  render() {
    return <div>{this.props.children}</div>;
  }
}

export default AppRoot;

方案2:React Router v4+(基于BrowserRouter)

如果你的项目用的是新版React Router,可以用Hook实现更简洁的逻辑:

import React, { useEffect } from 'react';
import { useLocation } from 'react-router-dom';

function AppRoot() {
  const location = useLocation();

  useEffect(() => {
    const executeScript = () => {
      if (document.readyState === 'complete') {
        runLogic();
      } else {
        const handleReady = () => {
          if (document.readyState === 'complete') {
            document.removeEventListener('readystatechange', handleReady);
            runLogic();
          }
        };
        document.addEventListener('readystatechange', handleReady);
      }
    };

    const runLogic = () => {
      // 检查页面资源加载状态(可选,根据你的需求决定是否保留)
      const unloadedImgs = Array.from(document.querySelectorAll('img')).filter(img => !img.complete);
      if (unloadedImgs.length === 0) {
        alert("It's loaded!");
      } else {
        let loadedCount = 0;
        const onImgDone = () => {
          loadedCount++;
          if (loadedCount === unloadedImgs.length) {
            unloadedImgs.forEach(img => {
              img.removeEventListener('load', onImgDone);
              img.removeEventListener('error', onImgDone);
            });
            alert("It's loaded!");
          }
        };
        unloadedImgs.forEach(img => {
          img.addEventListener('load', onImgDone);
          img.addEventListener('error', onImgDone);
        });
      }
    };

    executeScript();

    // 清理监听,避免内存泄漏
    return () => {
      document.removeEventListener('readystatechange', () => {});
    };
  }, [location]); // 每次路由变化时重新执行

  return <div>{/* 你的路由组件内容 */}</div>;
}

export default AppRoot;

关键说明

  1. 为什么之前的方法失效?:SPA路由切换时没有页面刷新,所以window.onload这类事件不会再次触发,必须通过路由监听+组件生命周期来捕获切换时机。
  2. 资源加载检查:如果你的脚本不需要等待图片等资源,直接在executeTargetScript里执行核心逻辑即可;如果需要等待资源,才需要添加图片加载状态的检查。
  3. 内存泄漏防范:一定要记得在组件卸载时移除路由监听和事件监听,避免内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:21:15