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

Next.js通过next/link跳转时next/script加载的第三方脚本失效问题

问题根因
  • beforeInteractive策略的脚本仅在应用首次硬加载时注入执行一次,你把jQuery、slick这类全局依赖放在首页组件里加载,客户端路由从其他页面跳回首页时,脚本不会重复执行,甚至可能出现依赖加载顺序错乱的问题。
  • 你写在functions.js里的slick初始化逻辑,默认绑定在页面首次DOM ready事件上,只会在硬刷新后触发一次。客户端路由切换时,轮播对应的DOM节点是React重新渲染生成的新节点,但初始化逻辑没有重新执行,slick实例没有绑定到新DOM上,功能自然失效。
修复方案

1. 全局依赖统一移到_document.js加载

把所有全站通用的第三方基础脚本从首页组件移到pages/_document.js中加载,保证所有路由场景下依赖都能提前按顺序加载完成,注意jQuery必须放在所有依赖它的插件前面:

// pages/_document.js
import { Html, Head, Main, NextScript } from 'next/document'
import Script from 'next/script'

export default function Document() {
  return (
    <Html lang="zh-CN">
      <Head />
      <body>
        <Main />
        <Script src="assets/js/jquery.min.js" strategy="beforeInteractive" />
        <Script src="assets/js/bootstrap.min.js" strategy="beforeInteractive" />
        <Script src="assets/js/slick.js" strategy="beforeInteractive" />
        <Script src="assets/js/jquery.fancybox.min.js" strategy="beforeInteractive" />
        <Script src="assets/js/wow.js" strategy="beforeInteractive" />
        <NextScript />
      </body>
    </Html>
  )
}

2. 组件内单独初始化slick

不要靠全局functions.js统一初始化插件,在轮播组件挂载完成后再执行slick初始化,组件卸载时销毁实例,从根源适配React的生命周期:

// components/MainSlider.js
import { useEffect, useRef } from 'react'

export default function MainSlider({ images }) {
  const sliderNode = useRef(null)

  useEffect(() => {
    // DOM渲染完成后初始化slick,配置和原项目保持一致
    if (window.$ && sliderNode.current) {
      window.$(sliderNode.current).slick({
        infinite: true,
        slidesToShow: 1,
        autoplay: true,
        // 其余原有slick配置项
      })
    }

    return () => {
      // 组件卸载时销毁实例,避免内存泄漏、重复绑定问题
      if (
        window.$ && 
        sliderNode.current && 
        window.$(sliderNode.current).hasClass('slick-initialized')
      ) {
        window.$(sliderNode.current).slick('unslick')
      }
    }
  }, [images])

  return (
    <div ref={sliderNode} className="slider-container">
      {images.map((item, idx) => (
        <div key={idx} className="slide-item">
          <img src={item.src} alt={item.alt} />
        </div>
      ))}
    </div>
  )
}

其他说明

  • functions.js里其余的插件初始化逻辑(WOW、fancybox、bootstrap事件绑定等),都要拆到对应业务组件的useEffect中执行,不要依赖全局一次性的DOM ready事件。
  • 如果暂时不想拆分原functions.js逻辑,可以通过Next.js路由事件监听,每次路由切换完成后重新执行全局初始化,但这种方式维护性差,容易出现重复绑定问题,仅适合临时兼容:
// 临时兼容方案,不推荐长期使用
import { useRouter } from 'next/router'
import Script from 'next/script'
import { useEffect } from 'react'

export default function HomePage() {
  const router = useRouter()
  const initPlugins = () => {
    // 执行原functions.js中的所有初始化逻辑
    if (window.$) {
      window.$('.slick-slider').not('.slick-initialized').slick({/* 原有配置 */})
      new window.WOW().init()
      window.$('[data-fancybox]').fancybox({/* 原有配置 */})
    }
  }

  useEffect(() => {
    router.events.on('routeChangeComplete', initPlugins)
    return () => router.events.off('routeChangeComplete', initPlugins)
  }, [router.events])

  return (
    <>
      <Script src="assets/js/functions.js" strategy="afterInteractive" onReady={initPlugins} />
      {/* 页面其余组件 */}
    </>
  )
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 08:54:22