index.tsx
TypeScript
import { FC, memo, PropsWithChildren, useEffect, useState, useRef, useMemo } from 'react'
import { Swiper as BaseSwiper, SwiperItem, View } from '@tarojs/components'
import { Button } from '@wmeimob/taro-design'
import classNames from 'classnames'
import styles from './index.module.less'
import Taro from '@tarojs/taro'
import { Flex } from '~/components'
import { vibrateShort } from '~/utils/util'
import { SwiperProps } from './const'
// import { getBarHeight } from '~/pages/service/util'
/**
* Swiper
* @param props
* @returns
*/
const Component: FC<PropsWithChildren<SwiperProps>> = ({ current, modes, isDot, onMode, children }) => {
const [currentIndex, setCurrentIndex] = useState(current ?? 0)
// const [dx, setDx] = useState(0)
const currentRef = useRef<number>(0)
useEffect(() => {
setCurrentIndex(current)
return () => {
Taro.setStorageSync('U1_LASTTIME_MODE_CURRENT', currentRef.current)
}
}, [current])
// const getScale = useMemo(() => {
// const { windowWidth } = Taro.getSystemInfoSync()
// return Math.min(Math.max(dx / (windowWidth - 20), 0.88), 1)
// }, [dx])
// console.log('Taro', Taro.getSystemInfoSync().windowWidth, getScale)
return (
<View className={styles.container}>
<BaseSwiper
// autoplay
// interval={2500}
easingFunction='easeOutCubic'
circular
duration={1000}
previousMargin='8px'
nextMargin='12px'
current={currentIndex}
className={styles.swiperBox}
onChange={(event) => {
setCurrentIndex(event.detail.current)
currentRef.current = event.detail.current
vibrateShort()
}}
// style={{
// height: Taro.getSystemInfoSync().windowHeight - getBarHeight() - 44 - 34
// }}
// onTransition={(event) => {
// console.log('onTransition', event.detail.dx)
// setDx(event.detail.dx)
// }}
>
{modes.map((mode, index) => {
return (
<SwiperItem key={`key-${index}`}>
<Flex
column
style={{
backgroundImage: `url(${mode?.bgImg})`
// transform: index === currentIndex ? ` scale(${getScale})` : undefined
}}
className={classNames(styles.swiperItem,{
[styles.swiperItemActive]: index === currentIndex,
[styles.swiperItemOutRight]: index > currentIndex,
[styles.swiperItemOutLeft]: index < currentIndex
})}
>
<Button
className={styles.button}
type="main"
text='开始护肤'
onClick={(event) => {
event.stopPropagation()
onMode?.(mode)
}}
/>
</Flex>
</SwiperItem>
)
})}
</BaseSwiper>
{isDot && (
<Flex alignCenter className={styles.dots}>
{modes.map((_, index) => {
return (
<View
key={`key-${index}`}
className={classNames(styles.dot, {
[styles.dotActive]: index === currentIndex
})}
/>
)
})}
</Flex>
)}
{children}
</View>
)
}
const Swiper = memo(Component)
export default Swiper
index.less
css
.container {
position: relative;
}
.swiperBox {
position: relative;
width: 100vw;
height: calc(100vw * 638 / 375);
.swiperItem {
position: relative;
width: calc(100% - 5px);
height: 100%;
background-size: cover;
background-repeat: no-repeat;
background-position: center;
border-radius: 8px;
margin-left: 5px;
padding: 15px;
.button {
position: absolute;
top: calc(100vw * 175 / 375);
width: 130px;
height: 42px;
border-radius: 42px;
background: #EFD7B1;
font-weight: 500;
}
}
.swiperItemActive {
transform: scale(1);
transition: all 0.8s ease 0s;
}
.swiperItemOutLeft {
transition: all 0.8s ease-out 0.1s;
transform: translate(20px, 38px) scale(0.88);
}
.swiperItemOutRight {
transition: all 0.8s ease-out 0.1s;
transform: translate(-20px, 38px) scale(0.88);
}
}
.dots {
position: absolute;
bottom: -15px;
// gap: 5px; // 有些手机型号无效
left: 50%;
transform: translateX(-50%);
z-index: 1000;
.dot {
width: 12px;
height: 2px;
background-color: #5B5C5C;
transition: all 0.5s;
margin-right: 5px;
}
.dotActive {
background-color: #fff;
}
}
conts.ts
TypeScript
export interface SwiperProps {
current: number
modes: xxxx[] // xxx是需要定义的inteface结构
isDot?: boolean
onMode?: (plan: CareModelDTO) => void
}
改造Swiper组件,符合业务的设计和动画效果