动态类名在 <swiper-slide 的复制项中没有起作用的解决方法
错误代码
<swiper:options="swiperOption"ref="mySwiper"class="bottom-ul"><swiper-slide v-for="(d, i) in bottomData":key="i"class="menu-item"><!--@click="btnClick(d.groupName)"--><liclass="menu-li":class="{ active: activeGroup === d.groupName }"><!--<i style=""><img:src="d.src"></i>--><span>{{d.groupName}}</span></li></swiper-slide>核心原因是复制的 slide 是 Swiper 纯 DOM 层面的复制,不会触发 Vue 的响应式渲染,所以复制项里的 Vue 指令(如 :class)完全失效。
问题本质拆解
v-for 只渲染了真实的 slide,这些 slide 内的<li>受 Vue 响应式控制,active 类名正常;
Swiper 开启 loop 后,会在 DOM 层面复制真实 slide 生成 duplicate 项,但复制的只是静态 DOM 结构,没有 Vue 的响应式绑定,所以 :class 指令不会执行,active 类名自然不会出现在复制项的<li>上;
当切换到复制 slide 时,视觉上看到的是复制项的<li>,但它没有 active 类,导致选中样式丢失。
解决方案:手动同步复制项的 active 类
核心思路是:监听 Swiper 的切换事件和 Vue 的 activeGroup 变化,手动给真实 slide + 复制 slide 中匹配的<li>添 / 删 active 类,绕过 Vue 响应式的限制。
<template><div><swiper:options="swiperOption"ref="mySwiper"class="bottom-ul"@slideChange="handleSlideChange"><swiper-slide v-for="(d, i) in bottomData":key="i"class="menu-item":data-group-name="d.groupName"<!--给真实slide标记分组名,方便DOM查找-->><liclass="menu-li":class="{ active: activeGroup === d.groupName }"><span>{{d.groupName}}</span></li></swiper-slide></swiper></div></template><script>import{Swiper,SwiperSlide}from'swiper/vue';import'swiper/css';import'swiper/css/navigation';import'swiper/css/pagination';importSwiperCorefrom'swiper';exportdefault{components:{Swiper,SwiperSlide},data(){return{bottomData:[// 示例数据{groupName:'分组1'},{groupName:'分组2'},{groupName:'分组3'},{groupName:'分组4'}],activeGroup:'分组2',// 默认选中的分组swiperOption:{centeredSlides:true,// 居中展示loop:true,// 循环(导致复制slide)slidesPerView:'auto',// 自适应宽度loopAdditionalSlides:5,// 增加复制slide数量initialSlide:1,// 初始从真实slide开始centeredSlidesBounds:false}};},watch:{// 监听activeGroup变化,同步更新所有slide(真实+复制)的active类activeGroup(newVal){this.syncActiveClass(newVal);}},mounted(){// 初始化时同步一次active类(确保复制项也有初始选中样式)this.$nextTick(()=>{this.syncActiveClass(this.activeGroup);});},methods:{// 核心方法:同步真实slide和复制slide的active类syncActiveClass(activeName){if(!this.$refs.mySwiper)return;// 1. 先移除所有slide内li的active类(避免多个active)document.querySelectorAll('.bottom-ul .menu-li').forEach(li=>{li.classList.remove('active');});// 2. 找到所有包含目标groupName的slide(真实+复制),给其li加active类consttargetSlides=document.querySelectorAll(`.bottom-ul .menu-item[data-group-name="${activeName}"]`);targetSlides.forEach(slide=>{constli=slide.querySelector('.menu-li');if(li)li.classList.add('active');});},// Swiper切换事件:同步activeGroup和active类handleSlideChange(){constswiperInstance=this.$refs.mySwiper.swiper;// 获取当前激活slide的真实索引constrealIndex=swiperInstance.realIndex;// 更新activeGroup为当前真实slide对应的分组名this.activeGroup=this.bottomData[realIndex].groupName;// 同步复制slide的active类this.syncActiveClass(this.activeGroup);},// 如果你有手动点击li的方法,也要同步调用syncActiveClassbtnClick(groupName){this.activeGroup=groupName;this.syncActiveClass(groupName);// 可选:点击后让对应的slide居中constswiperInstance=this.$refs.mySwiper.swiper;consttargetIndex=this.bottomData.findIndex(d=>d.groupName===groupName);swiperInstance.slideTo(targetIndex+1,300,true);// +1 适配loop的索引偏移}}};</script><style scoped>/* 示例样式:方便看选中效果 */.menu-li{list-style:none;padding:8px 16px;cursor:pointer;}.menu-li.active{background-color:#409eff;color:white;border-radius:4px;}.bottom-ul{width:100%;overflow:hidden;}.menu-item{display:inline-block;margin:08px;}</style>