Angular17 SSR中init为false时如何初始化主/缩略图Swiper(Swiper11.0.6)
解决Angular路由切换时Swiper缩略图组件异常问题
问题背景
在Angular组件中使用Swiper 11.0.6,当路由切换(含参数如/route/:id)时,主Swiper通过ngZone修复后功能正常,但缩略图Swiper仍表现异常。需要实现主Swiper与缩略图Swiper的关联初始化,确保路由切换时无缝运行。
解决方案代码
修改后的HTML
<div> <swiper-container #swiper1 style="--swiper-navigation-color: #fff; --swiper-pagination-color: #fff" class="mySwiper" navigation="true" init="false"> <swiper-slide *ngFor="let slide of slides"> <img [src]="slide.image" /> </swiper-slide> </swiper-container> <swiper-container #swiper2 class="mySwiper2" space-between="10" slides-per-view="6" free-mode="true" watch-slides-progress="true" init="false"> <swiper-slide *ngFor="let slide of slides"> <img [src]="slide.image" /> </swiper-slide> </swiper-container> </div>
CSS(无需修改)
swiper-slide { text-align: center; font-size: 18px; background: #fff; display: flex; justify-content: center; align-items: center; background-size: cover; background-position: center; img { display: block; width: 100%; height: 100%; object-fit: cover; } } .mySwiper { height: 600px; width: 100%; } .mySwiper2 { // defines height and width of thumbs swiper height: 100px; width: 100%; box-sizing: border-box; padding: 10px 0; swiper-slide { opacity: 0.6; // this set default opacity to all slides } .swiper-slide-thumb-active { opacity: 1; // this reset the opacity one for the active slide } }
修改后的TS代码
import { CommonModule } from '@angular/common'; import { Component, OnInit, CUSTOM_ELEMENTS_SCHEMA, ViewChild, ElementRef, OnDestroy, NgZone, } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { Subscription } from 'rxjs'; @Component({ selector: 'app-swiper-thumbs-vertical-dup-1', standalone: true, imports: [CommonModule], templateUrl: './swiper-thumbs-vertical-dup-1.component.html', styleUrl: './swiper-thumbs-vertical-dup-1.component.scss', schemas: [CUSTOM_ELEMENTS_SCHEMA] }) export class SwiperThumbsVerticalDup1Component implements OnInit, OnDestroy { @ViewChild('swiper1') swiper1!: ElementRef<any>; @ViewChild('swiper2') swiper2!: ElementRef<any>; slides: any[] = []; private routeSub!: Subscription; private swiper1Instance: any; private swiper2Instance: any; constructor(private zone: NgZone, private route: ActivatedRoute) { } ngOnInit() { this.routeSub = this.route.params.subscribe(params => { const id = params['id']; if (id == 1) { this.slides = [ { image: 'https://swiperjs.com/demos/images/nature-1.jpg' }, { image: 'https://swiperjs.com/demos/images/nature-2.jpg' }, { image: 'https://swiperjs.com/demos/images/nature-3.jpg' }, { image: 'https://swiperjs.com/demos/images/nature-4.jpg' }, { image: 'https://swiperjs.com/demos/images/nature-5.jpg' }, { image: 'https://swiperjs.com/demos/images/nature-6.jpg' }, { image: 'https://swiperjs.com/demos/images/nature-7.jpg' }, { image: 'https://swiperjs.com/demos/images/nature-8.jpg' }, { image: 'https://swiperjs.com/demos/images/nature-10.jpg' }, ]; } else { this.slides = [ { image: 'https://swiperjs.com/demos/images/nature-6.jpg' }, { image: 'https://swiperjs.com/demos/images/nature-7.jpg' }, { image: 'https://swiperjs.com/demos/images/nature-8.jpg' }, { image: 'https://swiperjs.com/demos/images/nature-10.jpg' }, { image: 'https://swiperjs.com/demos/images/nature-1.jpg' }, { image: 'https://swiperjs.com/demos/images/nature-2.jpg' }, { image: 'https://swiperjs.com/demos/images/nature-3.jpg' }, ]; } // 路由参数更新后重新初始化Swiper this.initSwipers(); }); } ngOnDestroy() { // 清理订阅与Swiper实例,避免内存泄漏 this.routeSub?.unsubscribe(); this.destroySwipers(); } private initSwipers() { // 先销毁旧实例 this.destroySwipers(); this.zone.runOutsideAngular(() => { // 初始化缩略图Swiper this.swiper2Instance = this.swiper2.nativeElement; Object.assign(this.swiper2Instance, { spaceBetween: 10, breakpoints: { 100: { slidesPerView: 3 }, 640: { slidesPerView: 5 }, 1024: { slidesPerView: 6 } }, freeMode: true, watchSlidesProgress: true }); this.swiper2Instance.initialize(); // 初始化主Swiper并关联缩略图实例 this.swiper1Instance = this.swiper1.nativeElement; Object.assign(this.swiper1Instance, { spaceBetween: 10, navigation: true, thumbs: { swiper: this.swiper2Instance } }); this.swiper1Instance.initialize(); }); } private destroySwipers() { if (this.swiper1Instance) { this.swiper1Instance.destroy(true, true); this.swiper1Instance = null; } if (this.swiper2Instance) { this.swiper2Instance.destroy(true, true); this.swiper2Instance = null; } } }
关键修改说明
- 移除类选择器关联:删除HTML中
thumbs-swiper=".mySwiper2",改为通过JS直接传递缩略图Swiper实例,避免路由切换后类选择器匹配错误。 - 封装初始化与销毁逻辑:
initSwipers函数先销毁旧实例,再按「缩略图→主Swiper」的顺序初始化,确保主Swiper能正确关联缩略图实例。destroySwipers函数在组件销毁或重新初始化前清理实例,防止内存泄漏。
- 路由参数更新触发初始化:在
route.params订阅回调中调用initSwipers,确保Slides更新完成后Swiper重新初始化。 - 保留
ngZone.runOutsideAngular:避免Swiper的DOM操作触发Angular变更检测,提升性能。
内容的提问来源于stack exchange,提问作者Vijai S
相关产品推荐
相关产品推荐

