Skip to content

制作modules模块

本文将手把手带你制作一个自己的modules模块。

前言

制作modules模块的核心方法是监听swiper的事件。可以通过文档中的事件查看详细的使用方法。

常用配置:

  • watchSlidesProgress:用于监听swiper-item的进度。
  • @beforeInit:用于在初始化swiper之前自定义,如添加类名。
  • @setTransition:为每个swiper-item设置过渡时间。
  • @setTranslate:为每个swiper-item定义详细动画。

首先应该做好swiper的基础建设,即正常实现一个swiper。

利用swiper提供的配置完善轮播效果。

通过setTranslate监听,为每个swiper-item设置transform zIndex opacity

通过setTransition监听,为每个swiper-item设置transitionDuration

制作modules

上面讲了怎样利用swiper的事件监听实现自定义的轮播效果。

那么如何将该轮播效果封装成modules呢?下面将详细介绍封装modules。

以全景轮播为示例。

第一步

基础建设

第二步

定义轮播效果需要用到的参数。

示例:

js
panorama: {
    // 全景轮播的深度
   depth: 300,
    // 全景轮播的旋转角度
   rotate: 50,
    // 全景轮播的拉伸距离
   stretch: 1
  }

第三步

实现全景轮播

第四步

接下来正式封装modules。

类型定义

首先新建一个轮播模块文件用于定义。示例命名:effect-panorama.ts

如果使用TypeScript,则需要定义类型。

js
// 导入swiper提供的初始化轮播效果方法
import effectInit from '@zebra-ui/swiper/components/shared/effect-init'
// 导入swiper参数类型
import type { SwiperInterface } from '@zebra-ui/swiper/types/swiper-class' //swiper实体类
import type { SwiperOptions } from '@zebra-ui/swiper/types/swiper-options' //swiper参数
import type { SwiperItemInstance } from '@zebra-ui/swiper/types/swiper-item-instance' //swiper-item实体

// 定义全景轮播的配置参数类型
export interface PanoramaEffectOptions {
  depth?: number
  rotate?: number
  stretch?: number
}

interface SwiperOptionsPanorama extends SwiperOptions {
  customEffect?: PanoramaEffectOptions
}

导出模块方法

回调里可接收三个参数。

  • swiper:swiper实例。
  • extendParams:合并配置方法。
  • on:swiper监听方法。
js
export default function EffectCoverflow({
  swiper,
  extendParams,
  on
}: {
  swiper: SwiperInterface
  extendParams: (params: Record<string, any>) => void
  on: (event: string, handler: (...args: any[]) => void) => void
}): void {


}

合并参数

使用extendParams方法合并配置参数。

js
export default function EffectCoverflow({
  swiper,
  extendParams,
  on
}: {
  swiper: SwiperInterface
  extendParams: (params: Record<string, any>) => void
  on: (event: string, handler: (...args: any[]) => void) => void
}): void {
  extendParams({ 
    // swiper提供了customEffect参数用于自定义配置
    customEffect: {
      depth: 300,
      rotate: 50,
      stretch: 1
    } as SwiperOptionsPanorama
  })
}

编写setTranslate

js
export default function EffectCoverflow({
  swiper,
  extendParams,
  on
}: {
  swiper: SwiperInterface
  extendParams: (params: Record<string, any>) => void
  on: (event: string, handler: (...args: any[]) => void) => void
}): void {
  extendParams({
    // swiper提供了customEffect参数用于自定义配置
    customEffect: {
      depth: 300,
      rotate: 50,
      stretch: 1
    } as SwiperOptionsPanorama
  })

    const setTranslate = () => { 
    const params = (swiper.params as SwiperOptionsPanorama)
      .customEffect as PanoramaEffectOptions
    const sizesGrid = swiper.slidesSizesGrid
    const { depth, rotate, stretch } = params
    const angleRad = (rotate! * Math.PI) / 180
    const halfAngleRad = angleRad / 2
    const angleModifier = 1 / (180 / rotate!)

    for (let i = 0; i < swiper.slides.length; i += 1) {
      const slideEl = swiper.slides[i]
      const slideProgress = (slideEl as SwiperItemInstance).progress
      const slideSize = sizesGrid[i]
      const progressModifier = swiper.params.centeredSlides
        ? 0
        : ((swiper.params.slidesPerView as number) - 1) * 0.5
      const modifiedProgress = slideProgress + progressModifier
      const angleCos = 1 - Math.cos(modifiedProgress * angleModifier * Math.PI)
      const translateX = `${modifiedProgress * ((stretch! * slideSize) / 3) * angleCos}px`
      const rotateY = modifiedProgress * rotate!
      const radius = (slideSize * 0.5) / Math.sin(halfAngleRad)
      const translateZ = `${radius * angleCos - depth!}px`
      slideEl.style.transform = `translateX(${translateX}) translateZ(${translateZ}) rotateY(${rotateY}deg)`
    }
  }
}

使用setTransition赋值过渡时间

js
export default function EffectCoverflow({
  swiper,
  extendParams,
  on
}: {
  swiper: SwiperInterface
  extendParams: (params: Record<string, any>) => void
  on: (event: string, handler: (...args: any[]) => void) => void
}): void {
  extendParams({
    // swiper提供了customEffect参数用于自定义配置
    customEffect: {
      depth: 300,
      rotate: 50,
      stretch: 1
    } as SwiperOptionsPanorama
  })

    const setTranslate = () => {
    const params = (swiper.params as SwiperOptionsPanorama)
      .customEffect as PanoramaEffectOptions
    const sizesGrid = swiper.slidesSizesGrid
    const { depth, rotate, stretch } = params
    const angleRad = (rotate! * Math.PI) / 180
    const halfAngleRad = angleRad / 2
    const angleModifier = 1 / (180 / rotate!)

    for (let i = 0; i < swiper.slides.length; i += 1) {
      const slideEl = swiper.slides[i]
      const slideProgress = (slideEl as SwiperItemInstance).progress
      const slideSize = sizesGrid[i]
      const progressModifier = swiper.params.centeredSlides
        ? 0
        : ((swiper.params.slidesPerView as number) - 1) * 0.5
      const modifiedProgress = slideProgress + progressModifier
      const angleCos = 1 - Math.cos(modifiedProgress * angleModifier * Math.PI)
      const translateX = `${modifiedProgress * ((stretch! * slideSize) / 3) * angleCos}px`
      const rotateY = modifiedProgress * rotate!
      const radius = (slideSize * 0.5) / Math.sin(halfAngleRad)
      const translateZ = `${radius * angleCos - depth!}px`
      slideEl.style.transform = `translateX(${translateX}) translateZ(${translateZ}) rotateY(${rotateY}deg)`
    }
  }

    const setTransition = (duration: number) => { 
    swiper.slides.forEach((el: { style: { transitionDuration: string } }) => {
      el.style.transitionDuration = `${duration}ms`
    })
  }
}

使用effectInit初始化轮播效果

swiper内部提供了effectInit方法。

js
export default function EffectCoverflow({
  swiper,
  extendParams,
  on
}: {
  swiper: SwiperInterface
  extendParams: (params: Record<string, any>) => void
  on: (event: string, handler: (...args: any[]) => void) => void
}): void {
  ...
  effectInit({  
    effect: 'panorama',  // 轮播效果名称
    swiper,
    on,
    setTranslate,
    setTransition,
    perspective: () => true,
    overwriteParams: () => ({
      watchSlidesProgress: true
    })
  })
}

这样,整个模块的编写就完成了。

使用模块

通过引入effect-panorama.ts文件后,配置:modules="[EffectPanorama]"后,设置effectpanorama即可使用模块。(与其他模块使用方式一致)

自定义参数实现反向全景

swiper提供了customEffect配置,用于接收自定的轮播效果中的参数。

通过将rotate旋转定义为负数,从而实现反向全景轮播。

完整代码

js
// effect-panorama.ts

import effectInit from '@zebra-ui/swiper/components/shared/effect-init'
import type { SwiperInterface } from '@zebra-ui/swiper/types/swiper-class'
import type { SwiperOptions } from '@zebra-ui/swiper/types/swiper-options'
import type { SwiperItemInstance } from '@zebra-ui/swiper/types/swiper-item-instance'

export interface PanoramaEffectOptions {
  depth?: number
  rotate?: number
  stretch?: number
}

interface SwiperOptionsPanorama extends SwiperOptions {
  customEffect?: PanoramaEffectOptions
}

export default function EffectPanorama({
  swiper,
  extendParams,
  on
}: {
  swiper: SwiperInterface
  extendParams: (params: Record<string, any>) => void
  on: (event: string, handler: (...args: any[]) => void) => void
}): void {
  extendParams({
    customEffect: {
      depth: 300,
      rotate: 50,
      stretch: 1
    } as SwiperOptionsPanorama
  })

  const setTranslate = () => {
    const params = (swiper.params as SwiperOptionsPanorama)
      .customEffect as PanoramaEffectOptions
    const sizesGrid = swiper.slidesSizesGrid
    const { depth, rotate, stretch } = params
    const angleRad = (rotate! * Math.PI) / 180
    const halfAngleRad = angleRad / 2
    const angleModifier = 1 / (180 / rotate!)

    for (let i = 0; i < swiper.slides.length; i += 1) {
      const slideEl = swiper.slides[i]
      const slideProgress = (slideEl as SwiperItemInstance).progress
      const slideSize = sizesGrid[i]
      const progressModifier = swiper.params.centeredSlides
        ? 0
        : ((swiper.params.slidesPerView as number) - 1) * 0.5
      const modifiedProgress = slideProgress + progressModifier
      const angleCos = 1 - Math.cos(modifiedProgress * angleModifier * Math.PI)
      const translateX = `${modifiedProgress * ((stretch! * slideSize) / 3) * angleCos}px`
      const rotateY = modifiedProgress * rotate!
      const radius = (slideSize * 0.5) / Math.sin(halfAngleRad)
      const translateZ = `${radius * angleCos - depth!}px`
      slideEl.style.transform = `translateX(${translateX}) translateZ(${translateZ}) rotateY(${rotateY}deg)`
    }
  }

  const setTransition = (duration: number) => {
    swiper.slides.forEach((el: { style: { transitionDuration: string } }) => {
      el.style.transitionDuration = `${duration}ms`
    })
  }

  effectInit({
    effect: 'panorama',
    swiper,
    on,
    setTranslate,
    setTransition,
    perspective: () => true,
    overwriteParams: () => ({
      watchSlidesProgress: true
    })
  })
}
css
/* effect-panorama.scss */
.swiper-panorama {
  overflow: visible;
  .swiper-slide {
    backface-visibility: hidden;
  }
}

轮播效果征集

分享制作的轮播效果,将有机会被zebra-swiper收录并署名。

可通过群聊联系我们:群聊

Released under the MIT License.