生产环境切换页面时,基于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
相关产品推荐
相关产品推荐

