龙空技术网

React-native多级联动PickerAlert封装

ZC超超 124

前言:

现在各位老铁们对“react select联动”大体比较着重,小伙伴们都需要知道一些“react select联动”的相关知识。那么小编同时在网上搜集了一些对于“react select联动””的相关内容,希望咱们能喜欢,朋友们快快来学习一下吧!

import {  View,  Text,  TouchableWithoutFeedback,  TouchableOpacity,  FlatList,} from 'react-native'import React,{  PureComponent,  Component,} from 'react'import _ from 'lodash'import styleSheet, {getThemeColor} from '../utils/styleSheet'import {Callback} from "modern/types/lang";import Modal from './Modal'import {getScreenHeight, getScreenWidth} from "modern/consts/ui-common";const styles = styleSheet.create({  container:{    flex:1,    backgroundColor: 0x00000074,    alignItems: 'center',    justifyContent: 'flex-end',  },  contentView:{    flexDirection:'row',    justifyContent: 'space-around',    backgroundColor: 'white'  },  stage:{    top:0,    bottom:0,    left:0,    right:0,    position:'absolute',    zIndex:10,    flexDirection:'row',    justifyContent: 'space-around',  },  maskView:{    left:0,    right:0,    position:'absolute',    top:0,    bottom:0,    zIndex:0,    justifyContent:'space-between'  },  emptyView:{    height:50,    flexDirection:'row',    justifyContent:'space-between',    paddingHorizontal:20,    backgroundColor: 'white',  },  maskStyle:{    width:'100%',    backgroundColor:'rgba(232,232,232,0.9)',    borderColor:"rgb(181,181,181)"  },  headerBtnView:{    height:50,justifyContent: 'center'  },  cancelText:{    fontSize:16,color:'gray'  }})interface ISHeadProps {  customHead:any,  confirm:Callback,  hide:Callback,  headOptions:any}const Head:React.FC<ISHeadProps> = React.memo(({customHead,confirm,hide,headOptions})=>{    if(customHead){      return customHead    }    const {      cancelTextStyle={},      cancelBtnView={},      confirmBtnView={},      confirmTextStyle={},      leftText='取消',      rightText='确定',      headerContainView={},    } = headOptions    return <View style={[styles.emptyView,headerContainView]}>      <TouchableOpacity style={[styles.headerBtnView,cancelBtnView]} onPress={hide}>        <Text style={[styles.cancelText,cancelTextStyle]}>{leftText}</Text>      </TouchableOpacity>      <TouchableOpacity onPress={confirm} style={[styles.headerBtnView,confirmBtnView]}>        <Text style={[{color:getThemeColor(),fontSize:16},confirmTextStyle]}>{rightText}</Text>      </TouchableOpacity>    </View>})interface ISEmpty {  hide:Callback}const Empty:React.FC<ISEmpty> = React.memo(({hide})=>{  return <TouchableWithoutFeedback  onPress={hide}>    <View style={{flex:1,width:getScreenWidth()}} />  </TouchableWithoutFeedback>})interface ISMaskView {  maxLength:number,  itemHeihght:number,  maskOptions:any,}const MaskView:React.FC<ISMaskView> = React.memo(({maxLength,itemHeihght,maskOptions={}})=>{  const {    upMaskView,    bottomMaskView  } = maskOptions  const mid = Math.floor(maxLength/2)  return  <View style={[styles.maskView]}>    <View style={[styles.maskStyle,{height:itemHeihght*mid,borderBottomWidth:1,},upMaskView]}/>    <View style={[styles.maskStyle,{height:itemHeihght*mid,borderTopWidth:1,},bottomMaskView]}/>  </View>})interface ISourceType {  id:string,  name:string,  sub?:ISourceType[]  [propname:string]:any,}interface ISitemOptons  {  itemHeihght?:number,  maxLength?:5 | 7 | 9,  ActiveTextStyle?:any,  normalTextStyle?:any,}interface ISProps {  sourceData:ISourceType[],  cancel?:Callback,  confirm:Callback,  selectData:ISourceType[],  pickerType:'scroll' | 'click' | 'all',  customHead:any,  headOptions:any,  maskOptions:any,  itemOptons:itemOptons,}interface ISState {  visible:boolean,  floor:number,}function WithHeadAndMethod(WrapComponent:any){    return class PickerAlertView extends PureComponent<ISProps,ISState>{      public selectedData:ISourceType[] =[]      public static defaultProps = {        itemOptons:{},        selectData:[],        headOptions:{},        pickerType:'all',        maskOptions:{}      }      constructor(props:ISProps) {        super(props);        this.state = {          visible:false,          floor:this.getMaxFloor(),        }      }      public getMaxFloor = ()=>{        const { sourceData } = this.props        if(_.isEmpty(sourceData)) return 0        let floor:number = 1        function treeData(arr:any){          const sub:any = arr.find((item:any)=>item?.sub?.length > 0)          if(sub){            floor = floor + 1            let arr2:any = []            arr.forEach((item:any)=>{              if(item?.sub?.length>0){                arr2 = arr2.concat(item.sub)              }            })            treeData(arr2)          }        }        treeData(sourceData)        return floor      }      public show = ()=>{        this.setState({visible:true})      }      public confirm = ()=>{        const { confirm=_.noop } = this.props        this.hide()        confirm(this.selectedData)      }      public hide = ()=>{        const { cancel=_.noop } = this.props        cancel()        this.setState({visible:false})      }      public getSelected = ()=>this.selectedData      private setSelected = (item:ISourceType,floor:number)=>{        this.selectedData[floor] = item      }      public componentDidUpdate(preProps,prevState,snapshot){        if(!_.isEqual(this.props.sourceData,preProps.sourceData)){          this.setState({            floor:this.getMaxFloor()          })        }      }      public render(){        const {          visible,          floor,        } = this.state        const {          selectData,          sourceData,          pickerType,          customHead,          headOptions,          maskOptions,          itemOptons,        } = this.props        if(!visible) return null        if(!_.isEmpty(selectData) && selectData.length !== floor  ) return null        if(_.isEmpty(sourceData)) return  null        const {          maxLength=9,          itemHeihght=50,          ActiveTextStyle={},          normalTextStyle={}        }  = itemOptons        return (          <Modal            visible={visible}            animationType="slide"            transparent={true}          >            <View              style={styles.container}            >              <Empty hide={this.hide}/>              <View style={{ width:getScreenWidth()}}>                <Head                  headOptions={headOptions}                  hide={this.hide}                  confirm={this.confirm}                  customHead={customHead}                />                <View  style={[{height:itemHeihght*maxLength},styles.contentView]}>                  <View style={styles.stage}>                    <WrapComponent                      sourceList={sourceData}                      setSelect={this.setSelected}                      floor={floor}                      currentFloor={0}                      maxLength={maxLength}                      defaultSelected = {selectData}                      itemHeihght={itemHeihght}                      ActiveTextStyle={ActiveTextStyle}                      normalTextStyle={normalTextStyle}                      pickerType={pickerType}                    />                  </View>                  <MaskView                    maxLength={maxLength}                    itemHeihght={itemHeihght}                    maskOptions={maskOptions}                  />                </View>              </View>            </View>          </Modal>        )      }    }}interface ISItemProps {  sourceList:ISourceType[],  setSelect:Callback,  floor:number,  currentFloor:number,  maxLength: 5 | 7 | 9,  defaultSelected:ISourceType[],  itemHeihght:number,  ActiveTextStyle:any,  normalTextStyle:any,  pickerType:string}interface ISItemState {  nextData:ISourceType[],  currentChoose:ISourceType,  initialScrollIndex:number,  renderList:any[],}class PickerAlertViewItem extends PureComponent<ISItemProps,ISItemState> {  public scrollView:any  public flatEl:any  public currentItem:any  public itemEL:any  public config:any = {    waitForInteraction: false,    itemVisiblePercentThreshold:100,  }  public  constructor(props:ISItemProps) {    super(props);    this.state = {      nextData:this.defaultRenderList(),      currentChoose:this.getDefaultChoose(),      initialScrollIndex:this.getInitialScrollIndex(),      renderList:this.flatListData(),    }  }  public getInitialScrollIndex = ()=>{    const {defaultSelected,currentFloor,sourceList } = this.props    if(_.isEmpty(defaultSelected)) return 0    const initIndex = sourceList.findIndex(item=>item.id === defaultSelected[currentFloor]?.id)    return  initIndex<0?0:initIndex  }  public defaultRenderList = ()=>{    const { currentFloor, floor, defaultSelected, sourceList,} = this.props    const getDefaultList = ()=>{      if(currentFloor + 1 === floor )  return []      return sourceList.find(value=>value.id === defaultSelected[currentFloor].id)?.sub || []    }    const getNoFefault = ()=>this.props.sourceList?.[0]?.sub || []    return _.isEmpty(defaultSelected)?getNoFefault():getDefaultList()  }  public getDefaultChoose = ()=>{    const { defaultSelected, currentFloor, sourceList } = this.props    return _.isEmpty(defaultSelected)?sourceList?.[0]:defaultSelected[currentFloor]  }  public mid = ()=>{    const { maxLength } = this.props    return Math.floor(maxLength/2)  }  public  flatListData = (nextData:any[])=>{    const { sourceList } = this.props    const mid = this.mid()    const arr = Array(mid).fill({id:'',name:'',sub:[]})    const currentData = nextData?nextData:sourceList    return [...arr,...currentData,...arr]  }  public getItemLayout = (data:any,index:any) =>{    const { itemHeihght } = this.props    return {length: itemHeihght, offset: itemHeihght * index, index}  }  public renderItem = ({item,index,separators}:any)=>{    const { itemHeihght ,ActiveTextStyle,normalTextStyle,pickerType} = this.props    const {currentChoose} = this.state    const itemPress =  (pickerType === 'scroll' || item.id === currentChoose?.id)?_.noop:this.clickItem    return <TouchableWithoutFeedback  onPress={()=>itemPress(item,index)}>              <Text                numberOfLines={1}                style={[                  {                    height:itemHeihght,                    textAlign:'center',                    lineHeight:itemHeihght,                    opacity:0.8,                    paddingHorizontal: 10,                  },                  item.id === currentChoose?.id?ActiveTextStyle:normalTextStyle                ]}              >{item.name}</Text>            </TouchableWithoutFeedback>  }  public clickItem =(item:ISourceType,index:any)=>{    const mid = this.mid()    if(index<mid) return    if(!item) return    this.scrollToIndex(index)    this.chooseItem(index,item)  }  public  scrollToIndex = (index:any)=>{    if(this.flatEl){      this.flatEl.scrollToIndex({        index,        viewPosition:0.5,        animated:true      })    }  }  public  chooseItem = (index:number,item:ISourceType)=>{    const { setSelect,currentFloor } = this.props    setSelect(item,currentFloor)    this.setState({      currentChoose:item || {},      nextData:item?.sub || []    },()=>{      if(this.itemEL) this.itemEL.reduction()    })  }  public reduction=()=>{    const currentChoose = this.props.sourceList?.[0] || {}    const nextData = currentChoose?.sub || []    const mid = this.mid()    this.setState({      currentChoose,      nextData,      renderList:this.flatListData()    },()=>{      _.delay(()=>this.clickItem(currentChoose,mid),60)    })  }  public componentDidMount(){    this.initSelected()  }  public initSelected = ()=>{    const {setSelect,currentFloor } = this.props    const { currentChoose } = this.state    setSelect(currentChoose,currentFloor)    if(this.flatEl) this.flatEl.recordInteraction()  }  public render(){    const {      floor,      currentFloor,      setSelect,      defaultSelected,      maxLength,      itemHeihght=50,      ActiveTextStyle,      normalTextStyle,      pickerType    } = this.props    const {      nextData,      initialScrollIndex,      renderList,    } = this.state    const nextFloor = currentFloor + 1    return (      <>        <FlatList          style={{flex:1 }}          ref={ref=>this.flatEl = ref}          showsHorizontalScrollIndicator={false}          showsVerticalScrollIndicator={false}          keyExtractor={(item: object, index: number) => String(index)}          renderItem={this.renderItem}          viewabilityConfig={this.config}          data={renderList}          getItemLayout={this.getItemLayout}          initialScrollIndex={initialScrollIndex}          onMomentumScrollEnd={this._moveEnd}          scrollEnabled={pickerType === 'click'?false:true}        />        {          floor > nextFloor ?            <PickerAlertViewItem              ref={ref=>this.itemEL = ref}              sourceList={nextData}              floor={floor}              setSelect={setSelect}              currentFloor={nextFloor}              defaultSelected={defaultSelected}              maxLength={maxLength}              itemHeihght={itemHeihght}              ActiveTextStyle={ActiveTextStyle}              normalTextStyle={normalTextStyle}              pickerType={pickerType}            />:            null        }      </>    )  }  private _moveEnd=(e)=>{    const {itemHeihght} = this.props    const { renderList } = this.state    const contentOffset = e.nativeEvent.contentOffset.y;    const mid = this.mid()    const index = Math.round(contentOffset/itemHeihght)+mid    this.clickItem(renderList[index],index)  }}export default  WithHeadAndMethod(PickerAlertViewItem)

数据结构很简单

[  {  	id:"1',    name:'test1',    sub:[]  },  {    id:"2',   	name:'test2',    sub:[]  },]

有优化的地方;欢迎大家指正!一起进步!实践出真知

标签: #react select联动