开发者问题收集

NextJS 脚本标签

2022-10-24
3834

所以我已经尝试了很长时间了。

在这个网站上,我需要能够放置一个脚本标记,该标记将嵌入联系表单和新闻通讯注册表单等到特定页面。因此,例如在联系页面上,联系表单脚本标记将生效。

我尝试了许多不同的方法,但我无法获得我想要的结果,因为这似乎是一件非常基本的事情。

我发现它最初似乎运行良好,脚本标记有效,我在页面上看到了我期望的内容。但是当您离开该页面并返回时,脚本标记不会显示。只有当我再次刷新页面时,脚本标记应该输出的内容才会出现。

我假设发生这种情况是因为使用 Link 标记后,网站不会在导航之间重新加载,而是像 SPA 一样工作,无需重新加载,但正是这种刷新触发了脚本标记的执行。

在我对此的研究中,我看到人们建议不要使用 Link 标记,而只使用标记,因此当导航到页面时,它必须重新加载并强制显示脚本标记。只是在我的情况下,这不是一个真正的选择,因为我无法判断客户端决定在哪个页面输出脚本标记,因为该网站是完全动态的,并且能够通过 CMS 进行构建。

我试过:

使用脚本执行 dangerlySetInnerHTML 技巧。不幸的是,正如我上面描述的,同样的事情发生了

<div
  dangerouslySetInnerHTML={{__html: `<script src=""></script>`}}
/>

我也尝试过使用 next 的内置脚本标记 https://nextjs.org/docs/api-reference/next/script 和所有不同的策略道具。不幸的是,脚本内容要么根本没有显示,要么表现得和上面一样。

我还尝试过创建一个辅助函数,该函数仅在导航到页面后使用 useEffect 来插入脚本标记,如下所示:

import { useEffect } from "react"


const useScript = (url) => {

  useEffect(() => {
    const script = document.createElement("script")

    script.src = url
    script.async = true

    document.body.appendChild(script)

    return () => {
      document.body.removeChild(script)
    }
  }, [url])
}

export default useScript;

然后在组件输出到页面:

<div>
    {useScript("...")}
</div>

这确实有效!每次导航到带有脚本的页面时,它都会输出脚本标记的内容 - 无需刷新页面。唯一的问题是脚本标记的内容始终输出在页面底部、页脚下方和所有内容。与实际 useScript 在组件中的位置相反。

我尝试通过将脚本附加到组件中已经存在的 div 中来改变 useEffect 的工作方式:

import { useEffect } from "react"


const useScript = (url) => {

  useEffect(() => {
    const script = document.createElement("script")

    script.src = url
    script.async = true
    script.defer = true

    document.getElementById('scriptEx').appendChild(script)

    return () => {
      document.body.removeChild(script)
    }
  }, [url])
}

export default useScript;

但由于某种原因,这与之前的设置不同。导航到页面时,脚本标记的内容不会再次显示。

我发现的最后一个方法每次都有效,但似乎是一个非常荒谬的方法是将脚本标记放在 iFrame 中:

<iframe
    srcDoc={`
    <!doctype html>
    <html>
        <head>
        </head>
        <body>
            <div>
                <script src="..."></script>
    
            </div>
        </body>
    </html>
    `}
/>

一定有办法做这个看似简单的事情。

如果有人能提供帮助,我将不胜感激!

编辑 :下面是我使用 Next 的 Script 标签所看到的示例: https://i.sstatic.net/gMumx.png

下面是组成该页面的 jsx:


import Script from "next/script";


const example = () => {
    return (
        <div>
            The Nav is above this


            <div>
                <p>Container for the form</p>
                <Script src="//basingstokegov.uk.com/resources/sharing/embed.js?sharing=lp-embed&domain=basingstokegov.uk.com&id=3IWH-BN7%2Fthank-you%22" async />
            </div>


            The footer is below this
        </div>
    )
}

export default example
2个回答

如果您使用的是 NextJs,解决方案非常简单。从 v11.0 开始,Next 团队从库 next/script 中引入了 Script 组件 ,它类似于库 next/head 中的 Head 组件。基本上您需要做的是:

import Script from 'next/script'
export default function Home(){
   return(
      <>
         <Script src="#" async />
      </>
   )
}

您可以在此处阅读有关 Next 文档中脚本组件的更多信息: https://nextjs.org/docs/basic-features/script

Souhail Benlhachemi
2022-10-24

我认为您应该从具有 id scriptEx 的元素中删除子元素,就像从主体中删除脚本一样。我认为您所要做的就是放入

    return () => {
      document.getElementById('scriptEx').removeChild(script)
    }

而不是

    return () => {
      document.body.removeChild(script)
    }

编辑

我认为因为您正在使用 NextJS,所以您需要验证 document 是否存在于 useEffect 的顶部。如下所示:

useEffect(() => {
  // If there is no window
  if (typeof window === "undefined") return;
}, [])
Samy Rahmani
2022-10-24