如何使用 swiper 9 和 Angular

Rap*_*let 23 web-component custom-element angular swiper.js

我实际上正在迁移到 Angular 15,并看到swiper 9 已经退出了

它被写为一个简单npm i swiper且应该有效的方法,因为

所有主要浏览器和几乎所有框架都支持自定义元素。

但我有点迷失了,因为我无法再将其导入模块中

有人知道如何将最新的v9.0.0^swiper 版本与 Angular 一起使用吗?

Jus*_*lot 29

在AppModule中添加:

import {register} from 'swiper/element/bundle';

register();
Run Code Online (Sandbox Code Playgroud)

创建指令

import {AfterViewInit, Directive, ElementRef, Input} from '@angular/core';
import {SwiperOptions} from "swiper";

@Directive({
  selector: '[fmSwiper]',
  standalone: true,
})
export class SwiperDirective implements AfterViewInit {

  private readonly swiperElement: HTMLElement;

  @Input('config')
  config?: SwiperOptions;

  constructor(private el: ElementRef<HTMLElement>) {
    this.swiperElement = el.nativeElement;
  }

  ngAfterViewInit() {
    Object.assign(this.el.nativeElement, this.config);
    
    // @ts-ignore
    this.el.nativeElement.initialize();
  }
}
Run Code Online (Sandbox Code Playgroud)

在您的组件 ts 文件中添加

schemas: [CUSTOM_ELEMENTS_SCHEMA]
Run Code Online (Sandbox Code Playgroud)

设置您的 Swiper 配置。

例子:

import {Component, CUSTOM_ELEMENTS_SCHEMA, ViewEncapsulation} from '@angular/core';
import {CommonModule} from '@angular/common';
import {MainHeadingComponent} from "../main-heading/main-heading.component";
import {StreamItemComponent} from "./stream-item/stream-item.component";
import {A11y, Mousewheel, Navigation, Pagination, SwiperOptions} from 'swiper';
import {SwiperDirective} from "../../directives/swiper.directive";

@Component({
  selector: 'fm-streams-swiper',
  standalone: true,
  encapsulation: ViewEncapsulation.None,
  imports: [
    CommonModule,
    MainHeadingComponent,
    StreamItemComponent,
    SwiperDirective
  ],
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
  templateUrl: './streams-swiper.component.html',
})
export class StreamsSwiperComponent {

  sliders: string[] = [
    'Test 1',
    'Test 2',
    'Test 3',
    'Test 4',
    'Test 5',
    'Test 6',
    'Test 7',
    'Test 8',
    'Test 9',
  ]

  public config: SwiperOptions = {
    modules: [Navigation, Pagination, A11y, Mousewheel],
    autoHeight: true,
    spaceBetween: 20,
    navigation: false,
    pagination: {clickable: true, dynamicBullets: true},
    slidesPerView: 1,
    centeredSlides: true,
    breakpoints: {
      400: {
        slidesPerView: "auto",
        centeredSlides: false
      },
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

和 HMTL 文件:

  <swiper-container fmSwiper [config]="config" init="false" class="w-full">
    <swiper-slide class="w-[310px] sm:w-[450px] pb-6"
         *ngFor="let slider of sliders">
      <fm-stream-item></fm-stream-item>
    </swiper-slide>
  </swiper-container>
Run Code Online (Sandbox Code Playgroud)

这是我目前的解决方案。很高兴听到在 Angular 中实现新版本 Swiper 的更好方法:-)

Swiper 元素:核心版本和模块

  • 谢谢你!对我来说几乎完美。重新初始化组件时似乎出现问题,可能只是与离子相关。但似乎只需在 this.el.nativeElement.initialize(); 中添加 0ms 超时即可解决。 (3认同)
  • 为了删除 // @ts-ignore 您可以将该行更改为: constructor(private el: ElementRef&lt;HTMLElement &amp; {initialize: () =&gt; void }&gt;) { (3认同)

小智 14

将 CUSTOM_ELEMENTS_SCHEMA 添加到 AppModule 的 @NgModule 装饰器中。这可以确保 Angular 编译并忽略未知的swiper-containerswiper-slide自定义元素,并且编译时不会出现错误。

import {CUSTOM_ELEMENTS_SCHEMA, NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';

import {AppRoutingModule} from './app-routing.module';
import {AppComponent} from './app.component';

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, AppRoutingModule],
  providers: [],
  bootstrap: [AppComponent],
  schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class AppModule {}
Run Code Online (Sandbox Code Playgroud)

然后就可以将swiper-containerswiper-slide元素添加到模板中,但是代码不会做太多事情。初始化幻灯片时,我们需要调用文档中描述的寄存器函数。如果你查看Swiper 的源代码,就会发现这个函数需要初始化 DOM。这意味着您应该将其放置在组件和ngAfterViewInit生命周期挂钩中。这为我们提供了以下代码(请注意,参数可以以 kebab-case 形式传递):

import {AfterViewInit, Component, ElementRef, ViewChild} from '@angular/core';
import {register} from 'swiper/element/bundle';

@Component({
  selector: 'app-root',
  template: `
    <swiper-container initial-slide="0" slides-per-view="1">
      <swiper-slide>
        <h1>Slide 1</h1>
      </swiper-slide>
      <swiper-slide>
        <h1>Slide 2</h1>
      </swiper-slide>
      <swiper-slide>
        <h1>Slide 3</h1>
      </swiper-slide>
    </swiper-container>
  `,
})
export class AppComponent implements AfterViewInit {

  ngAfterViewInit(): void {
    register();
  }
}
Run Code Online (Sandbox Code Playgroud)

可以通过ViewChild装饰器来实现对Swiper实例的访问。为了演示这一点,我添加了一个函数,每次幻灯片更改时都会将当前幻灯片的索引打印到控制台。并非文档中描述的所有事件都可用但必须以小写形式书写。

import {AfterViewInit, Component, ElementRef, ViewChild} from '@angular/core';
import {register} from 'swiper/element/bundle';
import {Swiper} from 'swiper/types';

@Component({
  selector: 'app-root',
  template: `
    <swiper-container #swiperRef initial-slide="0" (swiperactiveindexchange)="onActiveIndexChange()" slides-per-view="1">
      <swiper-slide>
        <h1>Slide 1</h1>
      </swiper-slide>
      <swiper-slide>
        <h1>Slide 2</h1>
      </swiper-slide>
      <swiper-slide>
        <h1>Slide 3</h1>
      </swiper-slide>
    </swiper-container>
  `,
})
export class AppComponent implements AfterViewInit {
  @ViewChild('swiperRef')
  swiperRef: ElementRef | undefined;
  swiper?: Swiper;

  ngAfterViewInit(): void {
    register();
    this.swiper = this.swiperRef?.nativeElement.swiper;
  }

  onActiveIndexChange() {
    console.log(this.swiper?.activeIndex);
  }
}
Run Code Online (Sandbox Code Playgroud)


小智 6

swiper9 使使用变得简单,只需"schemas: [CUSTOM_ELEMENTS_SCHEMA],"在 module.ts 文件中提及组件的导入位置即可

//below steps are for module.ts file
// 1 step : 
import { CUSTOM_ELEMENTS_SCHEMA,} from '@angular/core';

// 2nd step: 
mention "schemas: [CUSTOM_ELEMENTS_SCHEMA]," inside @NgModule 

// 3rd step : 
import { register } from 'swiper/element/bundle';
              
// and  
register();
Run Code Online (Sandbox Code Playgroud)

现在您的代码按预期工作“添加以下代码在 html 文件中”

<swiper-container #swiper initial-slide="0">
  <swiper-slide>Slide 1</swiper-slide>
  <swiper-slide>Slide 2</swiper-slide>
  <swiper-slide>Slide 3</swiper-slide>
  <swiper-slide>Slide 4</swiper-slide>
  <swiper-slide>Slide 5</swiper-slide>
  <swiper-slide>Slide 6</swiper-slide>
  <swiper-slide>Slide 7</swiper-slide>
  <swiper-slide>Slide 8</swiper-slide>
  <swiper-slide>Slide 9</swiper-slide>
</swiper-container>
Run Code Online (Sandbox Code Playgroud)

没有任何错误


Rap*_*let 5

尽管我已经接受这个答案作为解决方案,但实际上我必须执行以下操作。这需要我在swiper.js 文档中找到的一些想法

这是我能找到的最优化和最干净的版本。

应用程序组件.ts

import { register } from 'swiper/element/bundle'

constructor() {
  register()
}
Run Code Online (Sandbox Code Playgroud)
  1. register()应该只调用一次,所以这app.component.ts是该去的地方。

组件.html

<swiper-container
  #swiperRef
  init="false"
>
  <swiper-slide *ngFor="let i of items; trackBy: trackByFn">
    <!-- slide -->
  </swiper-slide>
</swiper-container>
Run Code Online (Sandbox Code Playgroud)
  1. init="false"如果您愿意的话,会让您准备选项。还可以让您订阅更改,例如slideChange.

模块.ts

import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'

@NgModule({
  // ...
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
Run Code Online (Sandbox Code Playgroud)

注意:您必须在将使用 swiper 元素的组件中声明它,不要全局声明它

组件.ts

@ViewChild('swiperRef', { static: true })
  protected _swiperRef: ElementRef | undefined
swiper?: Swiper

ngOnInit() {
  this._initSwiper()
}

private _initSwiper() {
  const options: SwiperOptions = {
    pagination: { clickable: true },
    slidesPerView: 1,
    breakpoints: this._getBreakpoints(), // In case you wish to calculate base on the `items` length
  }

  const swiperEl = this._swiperRef.nativeElement
  Object.assign(swiperEl, options)

  swiperEl.initialize()

  if (this.swiper) this.swiper.currentBreakpoint = false // Breakpoint fixes
  this.swiper = this._swiperRef.nativeElement.swiper

  this.swiper.off('slideChange') // Avoid multiple subscription, in case you wish to call the `_initSwiper()` multiple time

  this.swiper.on('slideChange', () => { // Any change subscription you wish
    this.infinitLoad?.triggerOnScroll()
  })
}
Run Code Online (Sandbox Code Playgroud)

注意:swiper-container 不得位于*ngIf. 如果是,请更改.component.ts文件中的以下内容。

*ngIf 的工作环境

@ViewChild('swiperRef', { static: false }) // Change to "false"
  protected _swiperRef: ElementRef | undefined

itemsLoaded() { // Shall not be used in `ngOnInit` because it isn't rendered yet
  this._initSwiper()
}
Run Code Online (Sandbox Code Playgroud)
  1. 创建一个包含 的组件swiper-container以避免使用 *ngIf
  2. 等待 DOM 被渲染(我没有找到任何干净的方法来做到这一点,如果您有任何好的想法,欢迎更新该部分;)