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

生产环境切换页面时,基于swiper.js的JS滑块出现崩溃问题

生产环境下Swiper滑块切换页面后纵向布局崩溃问题

问题详情

  • 开发环境执行npm run dev时滑块显示正常,但生产环境(本地npm start或部署到Ubuntu服务器)中,从带有滑块的「services」「work」页面切换到无滑块页面后,滑块变为纵向排列,布局完全崩溃。
  • 技术栈:JS + Tailwind (PCSS) + React + Next.js

相关代码

ServiceSlider.js

import { Swiper, SwiperSlide } from 'swiper/react';
import 'swiper/css';
import 'swiper/css/free-mode';
import 'swiper/css/pagination';

// icons
import {
  RxCrop,
  RxDesktop,
  RxReader,
  RxRocket,
  RxArrowTopRight,
} from 'react-icons/rx';

import { FreeMode, Pagination } from 'swiper';

// data
const serviceData = [
  {
    icon: <RxDesktop />,
    title: 'Development',
    description: 'Script and web development, bug-fixing',
  },
  {
    icon: <RxCrop />,
    title: 'Design',
    description: 'Some kind of web-design, AI art generation',
  },
  {
    icon: <RxRocket />,
    title: 'PC Buiding',
    description: 'Servrer or personal PC building',
  },
  {
    icon: <RxReader />,
    title: 'Translation',
    description: 'Professional RU-ENG/ENG-RU translation',
  },
];

const ServiceSlider = () => {
  return ( 
    <Swiper 
      breakpoints={{
        320: {
          slidesPerView: 1,
          spaceBetween: 15,
        },

        640: {
          slidesPerView: 3,
          spaceBetween: 15,
        },
      }}
     freeMode={true}
      pagination={{
        clickable: true,
      }}
      modules={[FreeMode, Pagination]}
      className='h-[240px] sm:h-[340px]'
    >
      {
      serviceData.map((item, index) => {
          return (
            <SwiperSlide key={index}>
              <div className='bg-[rgba(65,47,123,0.15)] h-max rounded-lg px-6 py-8 flex
              sm:flex-col gap-x-6 sm:gap-x-0 group cursor-pointer hover:bg-[rgba(89,65,169,0.15)]
              transition-all duration-300'>
                {/* icon */}
                <div className='text-4xl text-accent mb-4'>
                  {item.icon}
                </div>
                {/* title & desc */}
                <div className='mb-8'>
                  <div className='mb-2 text-lg'>
                    {item.title}
                  </div>
                    <p className='max-w-[350px] leading-normal'>
                      {item.description}
                    </p>
                </div>
                {/* arrow */}
                <div className='text-3xl'>
                  <RxArrowTopRight className='group-hover:rotate-45
                  group-hover:text-accent transition-all duration-300'/>
                </div>
              </div>
            </SwiperSlide>
          );
        })}
    </Swiper>
  );
};
export default ServiceSlider;

集成滑块的Services页面组件

import ServiceSlider from '../../components/ServiceSlider';
import Bulb from '../../components/Bulb';
import Circles from '../../components/Circles';

// framer-motion
import { motion } from 'framer-motion';
import { fadeIn } from '../../variants';

const Services = () => {
  return ( 
    <div className='h-full bg-primary/30 py-36 flex items-center'>
      <Circles />
      <div className='container mx-auto'>
        <div className='flex flex-col xl:flex-row gap-x-8'>
          {/* text */}
          <div className='text-center flex xl:w-[30vw] flex-col lg:text-left 
          mb-4 xl:mb-0'>
              <motion.h2 
                variants={fadeIn('up, 0.3')} 
                initial="hidden" 
                animate="show"
                exit="hidden" 
                className='h2 xl:mt-8'
              >
              My Services <span className='text-accent'>.</span>
              </motion.h2>
              <motion.p 
                variants={fadeIn('up, 0.4')} 
                initial="hidden" 
                animate="show"
                exit="hidden" 
                className='mb-4 max-w-[400px] mx-auto lg:mx-0'>
                Thanks for visiting my website!
              </motion.p>
          </div>

          {/* Slider */}
          <motion.div 
            variants={fadeIn('down, 0.6')} 
            initial="hidden" 
            animate="show"
            exit="hidden" 
            className='w-full xl:max-w-[65%]'
          > 
            <ServiceSlider />
          </motion.div>
        </div>
      </div>
      <Bulb />
    </div>
  );
};
export default Services;

解决方案

1. 强制客户端渲染(Next.js 13+ App Router)

在ServiceSlider.js顶部添加客户端指令,避免SSR环境下Swiper无法正确初始化:

'use client';
// 其他导入代码

2. 监听路由变化,手动销毁Swiper实例

添加路由监听,在页面切换时销毁Swiper,避免残留DOM影响后续布局:

import { useRouter } from 'next/router';
import { useEffect, useRef } from 'react';
// 其他导入

const ServiceSlider = () => {
  const router = useRouter();
  const swiperRef = useRef(null);

  useEffect(() => {
    const handleRouteChange = () => {
      if (swiperRef.current?.swiper) {
        swiperRef.current.swiper.destroy(true, true);
      }
    };

    router.events.on('routeChangeComplete', handleRouteChange);
    return () => {
      router.events.off('routeChangeComplete', handleRouteChange);
      if (swiperRef.current?.swiper) {
        swiperRef.current.swiper.destroy(true, true);
      }
    };
  }, [router]);

  return (
    <Swiper
      ref={swiperRef}
      // 保留原有props
      breakpoints={{
        320: { slidesPerView: 1, spaceBetween: 15 },
        640: { slidesPerView: 3, spaceBetween: 15 },
      }}
      freeMode={true}
      pagination={{ clickable: true }}
      modules={[FreeMode, Pagination]}
      className='h-[240px] sm:h-[340px]'
    >
      {/* 滑块内容 */}
    </Swiper>
  );
};

3. 全局引入Swiper样式

在_app.js(Pages Router)或layout.js(App Router)中全局导入Swiper CSS,防止生产构建时样式丢失:

// _app.js 或 layout.js
import 'swiper/css';
import 'swiper/css/free-mode';
import 'swiper/css/pagination';

4. 动态导入组件并禁用SSR(Pages Router)

用dynamic导入滑块组件,强制客户端渲染:

// 在Services页面替换原有导入
import dynamic from 'next/dynamic';

const ServiceSlider = dynamic(() => import('../../components/ServiceSlider'), {
  ssr: false,
  loading: () => <div className='h-[340px] flex items-center justify-center'>加载中...</div>
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 16:40:56