11import React , { RefObject , useCallback , useEffect , useMemo , useRef , useState } from 'react' ;
2- import { isNumber } from 'lodash-es' ;
2+ import { isNumber , isObject } from 'lodash-es' ;
33import classNames from 'classnames' ;
44import { Property } from 'csstype' ;
55import useDefaultProps from '../hooks/useDefaultProps' ;
@@ -8,18 +8,11 @@ import forwardRefWithStatics from '../_util/forwardRefWithStatics';
88import { useSwipe } from '../_util/useSwipe' ;
99import parseTNode from '../_util/parseTNode' ;
1010import { StyledProps } from '../common' ;
11- import { SwiperChangeSource , SwiperNavigation , SwiperNavigationType , TdSwiperProps } from './type' ;
11+ import { SwiperChangeSource , SwiperNavigation , TdSwiperProps } from './type' ;
1212import { swiperDefaultProps } from './defaultProps' ;
1313import SwiperItem from './SwiperItem' ;
1414import SwiperContext , { SwiperItemReference } from './SwiperContext' ;
1515
16- const DEFAULT_SWIPER_NAVIGATION : SwiperNavigation = {
17- paginationPosition : 'bottom' ,
18- placement : 'inside' ,
19- showControls : false ,
20- type : 'dots' ,
21- } ;
22-
2316export interface SwiperProps extends TdSwiperProps , StyledProps {
2417 children ?: React . ReactNode ;
2518 touchable ?: boolean ;
@@ -30,6 +23,7 @@ enum SwiperStatus {
3023 IDLE = 'idle' , // 空闲状态
3124 SWITCHING = 'switching' , // 切换状态
3225 STARTDRAG = 'startdrag' , // 开始拖拽
26+ ENDDRAG = 'enddrag' , // 结束拖拽
3327}
3428
3529// swiper组件的动态style
@@ -100,38 +94,43 @@ const Swiper = forwardRefWithStatics(
10094 [ props . nextMargin ] ,
10195 ) ;
10296
103- // 导航器配置
104- const navigationConfig = useMemo ( ( ) => {
105- if ( navigation === true ) {
106- return DEFAULT_SWIPER_NAVIGATION ;
107- }
108- if ( typeof navigation === 'object' && navigation !== null ) {
109- return { ...DEFAULT_SWIPER_NAVIGATION , ...navigation } ;
110- }
111- return { } ;
112- } , [ navigation ] ) ;
113-
11497 // 是否是导航配置
115- const isSwiperNavigation = useMemo ( ( ) => Object . keys ( navigationConfig ) . length > 0 , [ navigationConfig ] ) ;
98+ const isSwiperNavigation = useMemo ( ( ) => {
99+ if ( ! navigation ) return false ;
100+ const { minShowNum, paginationPosition, placement, showControls, type } = navigation as any ;
101+ return (
102+ minShowNum !== undefined ||
103+ paginationPosition !== undefined ||
104+ placement !== undefined ||
105+ showControls !== undefined ||
106+ type !== undefined
107+ ) ;
108+ } , [ navigation ] ) ;
116109
117110 // 是否显示导航
118111 const enableNavigation = useMemo ( ( ) => {
119- if ( ! isSwiperNavigation ) return false ;
120- const { minShowNum } = navigationConfig ;
121- return minShowNum ? itemCount >= minShowNum : true ;
122- } , [ isSwiperNavigation , navigationConfig , itemCount ] ) ;
112+ if ( isSwiperNavigation ) {
113+ const nav = navigation as SwiperNavigation ;
114+ return nav ?. minShowNum ? itemCount >= nav ?. minShowNum : true ;
115+ }
116+ return isObject ( navigation ) ;
117+ } , [ isSwiperNavigation , navigation , itemCount ] ) ;
123118
124119 const isBottomPagination = useMemo ( ( ) => {
125120 if ( ! isSwiperNavigation || ! enableNavigation ) return false ;
126- const { paginationPosition, type } = navigationConfig ;
127- return ( ! paginationPosition || paginationPosition === 'bottom' ) && ( type === 'dots' || type === 'dots-bar' ) ;
128- } , [ enableNavigation , isSwiperNavigation , navigationConfig ] ) ;
121+ const nav = navigation as SwiperNavigation ;
122+ return (
123+ ( ! nav ?. paginationPosition || nav ?. paginationPosition === 'bottom' ) &&
124+ ( nav ?. type === 'dots' || nav ?. type === 'dots-bar' )
125+ ) ;
126+ } , [ enableNavigation , isSwiperNavigation , navigation ] ) ;
129127
130128 // 导航位置
131129 const navPlacement = useMemo ( ( ) => {
132130 if ( ! isSwiperNavigation ) return undefined ;
133- return navigationConfig . placement ;
134- } , [ isSwiperNavigation , navigationConfig ] ) ;
131+ const nav = navigation as SwiperNavigation ;
132+ return nav . placement ;
133+ } , [ isSwiperNavigation , navigation ] ) ;
135134
136135 const rootClass = useMemo (
137136 ( ) => [
@@ -145,7 +144,6 @@ const Swiper = forwardRefWithStatics(
145144
146145 const intervalTimer = useRef < any > ( null ) ; // 轮播计时器
147146 const durationTimer = useRef < any > ( null ) ; // 轮播动画计时器
148- const isMounted = useRef ( true ) ; // 组件挂载状态
149147 const [ itemChange , setItemChange ] = useState ( false ) ; // 是否处于轮播状态
150148 const [ swiperStatus , setSwiperStatus ] = useState ( SwiperStatus . IDLE ) ; // 轮播状态
151149 const [ swiperStyle , setSwiperStyle ] = useState < SwiperStyleState > ( {
@@ -319,14 +317,12 @@ const Swiper = forwardRefWithStatics(
319317 // 进入idle状态
320318 const enterIdle = useCallback ( ( axis : string ) => {
321319 navCtrlActive . current = false ;
322- if ( isMounted . current ) {
323- setSwiperStyle ( ( prevState ) => ( {
324- ...prevState ,
325- transition : 'none' ,
326- transform : `translate${ axis } (0)` ,
327- } ) ) ;
328- setSwiperStatus ( SwiperStatus . IDLE ) ;
329- }
320+ setSwiperStyle ( ( prevState ) => ( {
321+ ...prevState ,
322+ transition : 'none' ,
323+ transform : `translate${ axis } (0)` ,
324+ } ) ) ;
325+ setSwiperStatus ( SwiperStatus . IDLE ) ;
330326 } , [ ] ) ;
331327
332328 // 进入切换状态
@@ -342,13 +338,11 @@ const Swiper = forwardRefWithStatics(
342338 ) ;
343339 updateSwiperItemClassName ( index , loop ) ;
344340 setDotIndex ( ( ) => index ) ;
345- if ( isMounted . current ) {
346- setSwiperStyle ( ( prevState ) => ( {
347- ...prevState ,
348- transition : `transform ${ duration } ms` ,
349- transform : generateTransform ( axis , - step ) ,
350- } ) ) ;
351- }
341+ setSwiperStyle ( ( prevState ) => ( {
342+ ...prevState ,
343+ transition : `transform ${ duration } ms` ,
344+ transform : generateTransform ( axis , - step ) ,
345+ } ) ) ;
352346 setSwiperStatus ( SwiperStatus . SWITCHING ) ;
353347 } ,
354348 [ calculateSwiperItemIndex , duration , loop , updateSwiperItemClassName ] ,
@@ -360,36 +354,28 @@ const Swiper = forwardRefWithStatics(
360354 previousIndex . current = calculateItemIndex ( nextIndex . current , items . current . length , loop ) ;
361355 updateSwiperItemPosition ( axis , previousIndex . current , loop ) ;
362356 enterIdle ( axis ) ;
363- if ( isMounted . current ) {
364- setItemChange ( ( prevState ) => ! prevState ) ;
365- }
357+ setItemChange ( ( prevState ) => ! prevState ) ;
366358 } ,
367359 [ calculateItemIndex , enterIdle , loop , updateSwiperItemPosition ] ,
368360 ) ;
369361
370362 // 上一页
371- const goPrev = useCallback (
372- ( source : SwiperChangeSource ) => {
373- if ( disabled ) return ;
374- navCtrlActive . current = true ;
375- swiperSource . current = source ;
376- nextIndex . current = previousIndex . current - 1 ;
377- enterSwitching ( directionAxis , - 1 ) ;
378- } ,
379- [ disabled , enterSwitching , directionAxis ] ,
380- ) ;
363+ const goPrev = ( source : SwiperChangeSource ) => {
364+ if ( disabled ) return ;
365+ navCtrlActive . current = true ;
366+ swiperSource . current = source ;
367+ nextIndex . current = previousIndex . current - 1 ;
368+ enterSwitching ( directionAxis , - 1 ) ;
369+ } ;
381370
382371 // 下一页
383- const goNext = useCallback (
384- ( source : SwiperChangeSource ) => {
385- if ( disabled ) return ;
386- navCtrlActive . current = true ;
387- swiperSource . current = source ;
388- nextIndex . current = previousIndex . current + 1 ;
389- enterSwitching ( directionAxis , 1 ) ;
390- } ,
391- [ disabled , enterSwitching , directionAxis ] ,
392- ) ;
372+ const goNext = ( source : SwiperChangeSource ) => {
373+ if ( disabled ) return ;
374+ navCtrlActive . current = true ;
375+ swiperSource . current = source ;
376+ nextIndex . current = previousIndex . current + 1 ;
377+ enterSwitching ( directionAxis , 1 ) ;
378+ } ;
393379
394380 const onItemClick = ( ) => {
395381 if ( disabled ) return ;
@@ -467,24 +453,7 @@ const Swiper = forwardRefWithStatics(
467453 }
468454 } , [ props . height ] ) ;
469455
470- useEffect (
471- ( ) => ( ) => {
472- isMounted . current = false ;
473- if ( intervalTimer . current ) {
474- clearTimeout ( intervalTimer . current ) ;
475- intervalTimer . current = null ;
476- }
477- if ( durationTimer . current ) {
478- clearTimeout ( durationTimer . current ) ;
479- durationTimer . current = null ;
480- }
481- } ,
482- [ ] ,
483- ) ;
484-
485456 useEffect ( ( ) => {
486- if ( ! isMounted . current ) return ;
487-
488457 if ( intervalTimer . current ) {
489458 clearTimeout ( intervalTimer . current ) ;
490459 intervalTimer . current = null ;
@@ -510,6 +479,9 @@ const Swiper = forwardRefWithStatics(
510479 case SwiperStatus . STARTDRAG :
511480 nextIndex . current = previousIndex . current ;
512481 break ;
482+ case SwiperStatus . ENDDRAG :
483+ setSwiperStatus ( SwiperStatus . IDLE ) ;
484+ break ;
513485 }
514486 } , [ autoplay , directionAxis , duration , enterIdle , enterSwitching , interval , quitSwitching , swiperStatus , disabled ] ) ;
515487
@@ -546,7 +518,7 @@ const Swiper = forwardRefWithStatics(
546518 [ props . height ] ,
547519 ) ;
548520
549- const swiperNav = useMemo ( ( ) => {
521+ const swiperNav = ( ) => {
550522 // 如果 navigation 为 false,不显示导航
551523 if ( navigation === false ) return null ;
552524
@@ -555,25 +527,19 @@ const Swiper = forwardRefWithStatics(
555527 return parseTNode ( navigation ) ;
556528 }
557529
558- // 内置导航器配置
559- const navType = navigationConfig ?. type as SwiperNavigationType | undefined ;
560- const navPaginationPosition = navigationConfig ?. paginationPosition as string | undefined ;
561- const navPlacement = navigationConfig ?. placement as string | undefined ;
562- const navShowControls = navigationConfig ?. showControls as boolean | undefined ;
563-
564530 // dots
565- const dots = ( ) => {
566- if ( navType && [ 'dots' , 'dots-bar' ] . includes ( navType ) ) {
531+ const dots = ( navigation : SwiperNavigation ) => {
532+ if ( [ 'dots' , 'dots-bar' ] . includes ( navigation ?. type || '' ) ) {
567533 return (
568534 < >
569535 { items . current . map ( ( _ : any , index : number ) => (
570536 < span
571537 key = { `page${ index } ` }
572- className = { classNames ( [
573- `${ swiperNavClass } __${ navType } -item` ,
574- index === dotIndex ? `${ swiperNavClass } __${ navType } -item--active` : '' ,
575- `${ swiperNavClass } __${ navType } -item--${ direction } ` ,
576- ] ) }
538+ className = { classNames (
539+ `${ swiperNavClass } __${ navigation ?. type } -item` ,
540+ index === dotIndex ? `${ swiperNavClass } __${ navigation ?. type } -item--active` : '' ,
541+ `${ swiperNavClass } __${ navigation ?. type } -item--${ direction } ` ,
542+ ) }
577543 />
578544 ) ) }
579545 </ >
@@ -582,32 +548,32 @@ const Swiper = forwardRefWithStatics(
582548 } ;
583549
584550 // fraction
585- const fraction = ( ) => {
586- if ( navType === 'fraction' ) {
551+ const fraction = ( navigation : SwiperNavigation ) => {
552+ if ( navigation ?. type === 'fraction' ) {
587553 return < span > { `${ ( dotIndex ?? 0 ) + 1 } /${ items . current . length } ` } </ span > ;
588554 }
589555 } ;
590556
591- const typeNav = ( ) => {
592- if ( navType ) {
557+ const typeNav = ( navigation : SwiperNavigation ) => {
558+ if ( 'type' in navigation ) {
593559 return (
594560 < span
595- className = { classNames ( [
561+ className = { classNames (
596562 `${ swiperNavClass } --${ direction } ` ,
597- `${ swiperNavClass } __${ navType } ` ,
598- `${ swiperNavClass } --${ navPaginationPosition || 'bottom' } ` ,
599- `${ isBottomPagination && navPlacement ? `${ swiperNavClass } --${ navPlacement } ` : '' } ` ,
600- ] ) }
563+ `${ swiperNavClass } __${ navigation ?. type || '' } ` ,
564+ `${ swiperNavClass } --${ navigation ?. paginationPosition || 'bottom' } ` ,
565+ `${ isBottomPagination && navigation ?. placement ? `${ swiperNavClass } --${ navigation ?. placement } ` : '' } ` ,
566+ ) }
601567 >
602- { dots ( ) }
603- { fraction ( ) }
568+ { dots ( navigation ) }
569+ { fraction ( navigation ) }
604570 </ span >
605571 ) ;
606572 }
607573 } ;
608574
609- const controlsNav = ( ) => {
610- if ( ! isVertical && navShowControls ) {
575+ const controlsNav = ( navigation : SwiperNavigation ) => {
576+ if ( ! isVertical && ! ! navigation ?. showControls ) {
611577 return (
612578 < span className = { `${ swiperNavClass } __btn` } >
613579 < span className = { `${ swiperNavClass } __btn--prev` } onClick = { ( ) => goPrev ( 'nav' ) } />
@@ -617,29 +583,17 @@ const Swiper = forwardRefWithStatics(
617583 }
618584 } ;
619585
620- // 如果启用了内置导航器
621- if ( enableNavigation ) {
586+ if ( ! enableNavigation ) return '' ;
587+ if ( isSwiperNavigation ) {
622588 return (
623589 < >
624- { controlsNav ( ) }
625- { typeNav ( ) }
590+ { controlsNav ( navigation as SwiperNavigation ) }
591+ { typeNav ( navigation as SwiperNavigation ) }
626592 </ >
627593 ) ;
628594 }
629-
630- return null ;
631- } , [
632- navigation ,
633- navigationConfig ,
634- enableNavigation ,
635- isBottomPagination ,
636- dotIndex ,
637- direction ,
638- isVertical ,
639- goPrev ,
640- goNext ,
641- swiperNavClass ,
642- ] ) ;
595+ return isObject ( navigation ) ? '' : parseTNode ( navigation ) ;
596+ } ;
643597
644598 return (
645599 < div
@@ -665,7 +619,7 @@ const Swiper = forwardRefWithStatics(
665619 >
666620 < SwiperContext . Provider value = { memoProviderValues } > { parseTNode ( children ) } </ SwiperContext . Provider >
667621 </ div >
668- { swiperNav }
622+ { swiperNav ( ) }
669623 </ div >
670624 ) ;
671625 } ,
0 commit comments