如何将Trailforks第三方Widget转换为Next.js组件?(尝试后无效果)
在Next.js中嵌入Trailforks Region Info Widget的问题与解决
问题背景
我需要在Next.js应用中集成Trailforks的Region Info Widget,该Widget在纯HTML文件中可正常运行,但移植到Next.js组件后完全没有显示,检查元素面板也找不到相关脚本的痕迹,推测脚本未成功加载到页面中。
原始Widget代码(纯HTML可正常运行)
<!-- TRAILFORKS WIDGET START --> <div class="TrailforksRegionInfo" data-w="435px" data-h="150px" data-rid="6253" data-counts="1" data-stats="1" data-title="1" data-activitytype="1"></div> <script type="application/javascript" src="https://es.pinkbike.org/326/sprt/j/trailforks/iframeResizer.min.js"></script> <script type="text/javascript"> var script = document.createElement("script"); script.setAttribute("src", "https://es.pinkbike.org/ttl-86400/sprt/j/trailforks/widget.js"); document.getElementsByTagName("head")[0].appendChild(script); var widgetCheck = false; </script> <!-- TRAILFORKS WIDGET END -->
我尝试的Next.js组件代码(无显示)
import Head from "next/head" export default function RegionInfo() { return <div className="h-96 w-96 bg-black"> <Head> <script type="application/javascript" src="https://es.pinkbike.org/326/sprt/j/trailforks/iframeResizer.min.js"></script> <script type="text/javascript" dangerouslySetInnerHTML={{ __html: ` var script = document.createElement("script"); script.setAttribute("src", "https://es.pinkbike.org/ttl-86400/sprt/j/trailforks/widget.js"); document.getElementsByTagName("head")[0].appendChild(script); var widgetCheck = false;`}} /> </Head> <div className="TrailforksRegionInfo" data-w="435px" data-h="150px" data-rid="6253" data-counts="1" data-stats="1" data-title="1" data-activitytype="1"></div> </div> }
解决方案
问题出在脚本加载的时机和Next.js的渲染机制上:直接在Head组件的dangerouslySetInnerHTML中动态创建脚本,可能因为服务端渲染时没有document对象,或者脚本加载逻辑未正确触发。
修正后的组件代码如下,使用useEffect确保脚本在客户端环境下加载,并且保证依赖脚本先加载完成:
import { useEffect } from 'react'; export default function RegionInfo() { useEffect(() => { // 先加载iframeResizer脚本 const iframeResizerScript = document.createElement('script'); iframeResizerScript.src = 'https://es.pinkbike.org/326/sprt/j/trailforks/iframeResizer.min.js'; iframeResizerScript.type = 'application/javascript'; // 加载完成后再加载widget脚本 iframeResizerScript.onload = () => { const widgetScript = document.createElement('script'); widgetScript.src = 'https://es.pinkbike.org/ttl-86400/sprt/j/trailforks/widget.js'; widgetScript.type = 'text/javascript'; document.head.appendChild(widgetScript); }; document.head.appendChild(iframeResizerScript); // 清理函数,组件卸载时移除脚本 return () => { document.head.removeChild(iframeResizerScript); const widgetScript = document.querySelector('script[src="https://es.pinkbike.org/ttl-86400/sprt/j/trailforks/widget.js"]'); if (widgetScript) document.head.removeChild(widgetScript); }; }, []); return ( <div className="h-96 w-96 bg-black"> <div className="TrailforksRegionInfo" data-w="435px" data-h="150px" data-rid="6253" data-counts="1" data-stats="1" data-title="1" data-activitytype="1"></div> </div> ); }
关键说明
- 使用
useEffect钩子,第二个参数传空数组确保只在组件挂载时执行一次,且仅在客户端运行。 - 通过
onload事件保证iframeResizer.min.js加载完成后再加载widget.js,避免依赖问题。 - 添加清理函数,在组件卸载时移除脚本,防止内存泄漏。
内容的提问来源于stack exchange,提问作者Igor L.
相关产品推荐
相关产品推荐

