import { Component , h , ComponentInterface , Prop , Host , State , Listen } from '@stencil/core' ; import { TOP , LINE_HEIGHT , MASK_HEIGHT } from './constant' ; @ Component ( { tag : 'taro-picker-group' } ) export class TaroPickerGroup implements ComponentInterface { @ Prop ( ) mode : 'time' | 'date' ; @ Prop ( ) range : any [ ] = [ ] ; @ Prop ( ) rangeKey : string ; @ Prop ( ) height : number ; @ Prop ( ) columnId : string ; @ Prop ( ) updateHeight : ( height : number , columnId : string , needRevise ? : boolean ) => void ; @ Prop ( ) onColumnChange : ( height : number , columnId : string ) => void ; @ Prop ( ) updateDay : ( value : number , fields : number ) => void ; @ State ( ) startY : number ; @ State ( ) preY : number ; @ State ( ) hadMove : boolean ; @ State ( ) touchEnd : boolean ; @ State ( ) isMove : boolean ; getPosition ( ) { const transition = this . touchEnd ? 0.3 : 0 ; const transformValue = `translate3d(0, ${ this . height }px, 0)` ; const transitionValue = `transform ${ transition }s` ; return { transform : transformValue , '-webkit-transform' : transformValue , transition : transitionValue , '-webkit-transition' : transitionValue } ; } formulaUnlimitedScroll ( range , absoluteHeight , direction ) { const { height , updateHeight , columnId } = this ; const factor = direction === 'up' ? 1 : - 1 ; this . touchEnd = false ; updateHeight ( - range * factor * LINE_HEIGHT + height , columnId ) ; requestAnimationFrame ( ( ) => { this . touchEnd = true ; const index = Math . round ( absoluteHeight / - LINE_HEIGHT ) + range * factor ; const relativeHeight = TOP - LINE_HEIGHT * index ; updateHeight ( relativeHeight , columnId , true ) ; } ) ; } handleMoveStart ( clientY ) { this . startY = clientY ; this . preY = clientY ; this . hadMove = false ; } handleMoving ( clientY ) { const y = clientY ; const deltaY = y - this . preY ; this . preY = y ; this . touchEnd = false ; if ( Math . abs ( y - this . startY ) > 10 ) this . hadMove = true ; let newPos = this . height + deltaY ; if ( this . mode === 'time' ) { if ( this . columnId === '0' ) { if ( newPos > TOP - LINE_HEIGHT * 3 ) { newPos = TOP - LINE_HEIGHT * 27 + deltaY ; } if ( newPos < TOP - LINE_HEIGHT * 28 ) { newPos = TOP - LINE_HEIGHT * 4 + deltaY ; } } else if ( this . columnId === '1' ) { if ( newPos > TOP - LINE_HEIGHT * 3 ) { newPos = TOP - LINE_HEIGHT * 63 + deltaY ; } if ( newPos < TOP - LINE_HEIGHT * 64 ) { newPos = TOP - LINE_HEIGHT * 4 + deltaY ; } } } this . updateHeight ( newPos , this . columnId ) ; } handleMoveEnd ( clientY ) { const { mode , range , height , updateHeight , onColumnChange , columnId } = this ; const max = 0 ; const min = - LINE_HEIGHT * ( range . length - 1 ) ; const endY = clientY ; this . touchEnd = true ; let absoluteHeight ; if ( ! this . hadMove ) { /** 点击 */ const windowHeight = window . innerHeight ; const relativeY = windowHeight - MASK_HEIGHT / 2 ; absoluteHeight = height - TOP - ( endY - relativeY ) ; if ( mode === 'time' ) { if ( columnId === '0' ) { if ( absoluteHeight > - LINE_HEIGHT * 2.5 ) { return this . formulaUnlimitedScroll ( 24 , absoluteHeight , 'up' ) ; } if ( absoluteHeight < - LINE_HEIGHT * 28.5 ) { return this . formulaUnlimitedScroll ( 24 , absoluteHeight , 'down' ) ; } } else if ( columnId === '1' ) { if ( absoluteHeight > - LINE_HEIGHT * 2.5 ) { return this . formulaUnlimitedScroll ( 60 , absoluteHeight , 'up' ) ; } if ( absoluteHeight < - LINE_HEIGHT * 64.5 ) { return this . formulaUnlimitedScroll ( 60 , absoluteHeight , 'down' ) ; } } } } else { /** 滚动 */ absoluteHeight = height - TOP ; } if ( absoluteHeight > max ) absoluteHeight = 0 ; if ( absoluteHeight < min ) absoluteHeight = min ; const index = Math . round ( absoluteHeight / - LINE_HEIGHT ) ; const relativeHeight = TOP - LINE_HEIGHT * index ; if ( this . mode === 'date' ) { if ( this . columnId === '0' ) { this . updateDay ( + this . range [ index ] . replace ( /[^0-9]/gi , '' ) , 0 ) ; } if ( this . columnId === '1' ) { this . updateDay ( + this . range [ index ] . replace ( /[^0-9]/gi , '' ) , 1 ) ; } if ( this . columnId === '2' ) { this . updateDay ( + this . range [ index ] . replace ( /[^0-9]/gi , '' ) , 2 ) ; } } updateHeight ( relativeHeight , columnId , mode === 'time' ) ; onColumnChange && onColumnChange ( relativeHeight , columnId ) ; } @ Listen ( 'mousedown' ) onMouseDown ( e ) { this . isMove = true ; this . handleMoveStart ( e . clientY ) ; } @ Listen ( 'mousemove' ) onMouseMove ( e ) { e . preventDefault ( ) ; if ( ! this . isMove ) return ; this . handleMoving ( e . clientY ) ; } @ Listen ( 'mouseup' ) @ Listen ( 'mouseleave' ) onMouseMoveEnd ( e ) { if ( ! this . isMove ) return ; this . isMove = false ; this . handleMoveEnd ( e . clientY ) ; } @ Listen ( 'touchstart' ) onTouchStart ( e ) { this . handleMoveStart ( e . changedTouches [ 0 ] . clientY ) ; } @ Listen ( 'touchmove' ) onTouchMove ( e ) { e . preventDefault ( ) ; this . handleMoving ( e . changedTouches [ 0 ] . clientY ) ; } @ Listen ( 'touchend' ) onTouchEnd ( e ) { this . handleMoveEnd ( e . changedTouches [ 0 ] . clientY ) ; } render ( ) { const { range , rangeKey } = this ; const pickerItem = range . map ( item => { const content = rangeKey ? item [ rangeKey ] : item ; return ( < div class = 'weui-picker__item' > { content } < /div>); } ) ; return ( < Host class = 'weui-picker__group' > < div class = 'weui-picker__mask' / > < div class = 'weui-picker__indicator' / > < div class = 'weui-picker__content' style = { this . getPosition ( ) } > { pickerItem } < /div> < /Host>); } }