React DOM渲染完成后执行Vanilla JS脚本的问题咨询
你遇到的问题本质是静态HTML加载完成时,React还未将组件内容挂载到#root节点上。浏览器解析到body末尾的脚本时,#root还只是个空的div,动态生成的DOM元素还不存在,所以脚本报错。
下面是不同场景的解决方案:
方案1:在React挂载完成的回调中加载脚本(最推荐)
React提供了挂载完成的回调,此时所有组件对应的DOM已经完全生成,是执行第三方动画脚本的最佳时机。
操作步骤:
- 先删除
index.html中所有非基础依赖的动画相关的script标签,保留jQuery、Bootstrap这类基础依赖脚本即可,避免重复加载冲突。 - 在React应用入口文件(一般为
src/index.js)中,将脚本加载逻辑写在挂载完成回调中:- React 17及更早版本写法:
import ReactDOM from 'react-dom'; import App from './App'; ReactDOM.render( <App />, document.getElementById('root'), async () => { // 按你原有顺序排列需要加载的脚本列表 const scriptList = [ "asset/js/polyfill.min.js", "asset/js/jquery.viewport.min.js", "asset/js/jQuerySimpleCounter.min.js", "asset/js/jquery.magnific-popup.min.js", "asset/js/animsition.min.js", "asset/js/isotope.pkgd.min.js", "asset/js/bootstrap.bundle.min.js", "asset/js/rellax.min.js", "asset/js/swiper.min.js", "asset/js/smoothscroll.js", "asset/js/svg4everybody.legacy.min.js", "asset/js/TweenMax.min.js", "asset/js/TimelineLite.min.js", "asset/js/typed.min.js", "asset/js/vivus.min.js", "asset/js/main.js", "asset/js/theme.js", "https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.6.0/slick.js", "asset/js/cutsom.js" ]; // 按顺序加载脚本,避免依赖顺序出错 const loadScript = (src) => { return new Promise((resolve, reject) => { const script = document.createElement('script'); script.src = src; script.onload = resolve; script.onerror = reject; document.body.appendChild(script); }) } for(const src of scriptList) { await loadScript(src); } } )
- React 18版本写法:
import { createRoot } from 'react-dom/client'; import App from './App'; const root = createRoot(document.getElementById('root')); root.render(<App />); // 监听挂载完成 root._internalRoot.callback = async () => { // 此处写入和上面相同的脚本加载逻辑即可 }
方案2:在根组件生命周期中加载脚本
如果不方便修改入口文件,也可以把脚本加载逻辑写在根组件的生命周期中:
import { useEffect } from 'react'; function App() { useEffect(() => { // 此处写入和上面相同的脚本加载逻辑即可 }, []); // 空依赖数组保证逻辑仅执行一次 // 原有组件业务逻辑 }
方案3:不修改React代码的兼容方案
如果不想改动任何React业务代码,只需要修改原有第三方脚本,可在所有脚本外层包裹元素存在性轮询逻辑:
// 放在你所有自定义逻辑的最外层 function initAllScripts() { // 把你原有脚本里的所有初始化逻辑放到这里 } function checkDomReady() { // 替换成你实际需要用到的元素ID,确认存在后再执行初始化 if(document.getElementById('你要检测的元素ID')) { initAllScripts(); } else { setTimeout(checkDomReady, 50); } } checkDomReady();
注意事项
- 你现有
index.html里有重复引入的jQuery和slick脚本,记得删除重复项,避免出现依赖冲突。 - 如果出现
$未定义的报错,确保jQuery脚本加载完成后再加载其他依赖jQuery的脚本。
内容的提问来源于stack exchange,提问作者Ahsan Alii
相关产品推荐
相关产品推荐

