React中useScript加载Bookeo组件部分浏览器无法渲染iframe问题
React动态加载Bookeo组件的浏览器兼容问题解决方案
问题分析
你当前用useScript钩子动态加载Bookeo组件时,出现Chrome(部分系统)、Edge浏览器无法渲染iframe的情况,但直接在index.html中添加script标签却能正常工作,核心原因在于:
- 动态脚本的执行时机与React组件的DOM渲染周期不同步,当脚本执行时,目标挂载容器可能还未完全插入DOM
- 直接加到body的脚本,无法让Bookeo widget精准定位到你指定的Grid容器,不同浏览器对DOM节点就绪的判断逻辑存在差异,导致渲染失败
解决方案1:指定挂载容器并同步脚本加载时机
修改useScript钩子,让脚本挂载到目标容器,并确保容器就绪后再加载脚本:
import { useEffect, useRef } from 'react'; const useScript = (url, containerRef) => { useEffect(() => { const targetElement = containerRef.current; if (!targetElement) return; // 避免重复加载脚本 const existingScript = targetElement.querySelector(`script[src="${url}"]`); if (existingScript) return; const script = document.createElement('script'); script.src = url; script.async = true; // 通过URL参数告诉Bookeo要挂载到哪个容器(参考Bookeo文档,部分widget支持container参数) script.src += `&container=${targetElement.id}`; targetElement.appendChild(script); return () => { if (script.parentNode) { script.parentNode.removeChild(script); } }; }, [url, containerRef]); }; // 组件内使用 const BookeoContainer = () => { const containerRef = useRef(null); return ( <Grid item xs={12} ref={containerRef} id="bookeo-widget-container"> {useScript("https://bookeo.com/widget.js?a=***************", containerRef)} </Grid> ); };
解决方案2:手动控制widget初始化(更可靠)
如果Bookeo提供了全局初始化API,直接封装成组件,精准控制初始化时机:
import { useEffect, useRef } from 'react'; const BookeoWidget = ({ accountId }) => { const containerRef = useRef(null); useEffect(() => { const container = containerRef.current; if (!container) return; // 检查脚本是否已加载 let scriptLoaded = !!document.querySelector('script[src*="bookeo.com/widget.js"]'); const initWidget = () => { // 调用Bookeo全局初始化方法(需参考官方文档确认API) if (window.Bookeo?.init) { window.Bookeo.init({ container: container.id, accountId: accountId }); } }; if (scriptLoaded) { initWidget(); return; } // 加载脚本并绑定加载完成事件 const script = document.createElement('script'); script.src = `https://bookeo.com/widget.js?a=${accountId}`; script.async = true; script.onload = initWidget; script.onerror = () => console.error('Bookeo脚本加载失败'); document.body.appendChild(script); // 组件卸载时清理 return () => { if (window.Bookeo?.destroy) { window.Bookeo.destroy(container.id); } script.parentNode?.removeChild(script); }; }, [accountId]); return <Grid item xs={12} ref={containerRef} id="bookeo-widget-container" />; }; // 使用示例 <BookeoWidget accountId="***************" />
额外优化点
- 用
useLayoutEffect替代useEffect:如果依然存在时机问题,useLayoutEffect会在DOM更新后同步执行,比异步的useEffect更适合确保容器就绪 - 添加加载状态:在组件中加入loading提示,提升用户体验
内容的提问来源于stack exchange,提问作者Cem Adatepe
相关产品推荐
相关产品推荐

