UNPKG

mh-rn-component

Version:

220 lines (219 loc) 6.92 kB
import React, { useRef, useEffect, useState } from 'react' import { View, Text, StyleSheet, FlatList, TouchableWithoutFeedback } from "react-native" import Columns from "./Columns" import Overlay from '../Overlay' import { multiColumnData, cascadeData } from "./data" import { CustomFieldNameType, PickerColumn, Numeric } from "./types" type Props = { show?: boolean, columns: Array<PickerColumn>,//* 数据 特定数据格式或自定义数据格式 title?: string,//*顶部栏标题 confirmButtonText?: string,//*确认按钮文字 cancelButtonText?: string,//*取消按钮文字 visibleItemCount?: number,//*可见选项个数 默认5 columnHeight?: number,//*选项高度 默认44 cascadeLevel?: number,//*启用级联选择 需要填写具体几层 减少代码量 优化点 customFieldName?: CustomFieldNameType,//*自定义 columns 结构中的字段 toolbar?: React.ReactElement<{}>//todo 自定义整个顶部栏内容 showChange: (value: boolean) => void onConfirm?: (currentValue: Numeric | Numeric[]) => void onCancel?: (currentValue?: Numeric | Numeric[]) => void onChange?: (currentValue: Numeric | Numeric[]) => void } const Picker = ( { show, title = "标题", confirmButtonText = "确认", cancelButtonText = "取消", visibleItemCount = 5, columnHeight = 44, columns, cascadeLevel, customFieldName = { value: "value", children: "children" }, toolbar, ...rest }: Props) => { const customFieldNameValue = customFieldName.value || "value" const customFieldNameChildren = customFieldName.children || "children" // 当前列的选项数组 const [columnsData, setColumnsData] = useState<any[]>([]) // 要返回的选中数组 const [currentValue, setCurrentValue] = useState<Numeric[]>(new Array(columnsData.length)) // 当前各列选中的index const [columnsSelect, setColumnsSelect] = useState(new Array(columnsData.length)) const formattedColumns = () => { // 判断是否事级联选择 if (cascadeLevel) { let cascadeArr = new Array(cascadeLevel) for (let i = 0; i < cascadeLevel; i++) { if (i === 0) { cascadeArr[0] = { values: columns } } else { cascadeArr[i] = { values: cascadeArr[i - 1]?.values[0][customFieldNameChildren], defaultIndex: 0 } } } setColumnsData(() => { return [...cascadeArr] }) } else { setColumnsData([...columns]) } } // 重组 级联数据结构 const cascadeFormat = (value: number, columnsIndex: number) => { for (let i = columnsIndex + 1; i < columnsData.length; i++) { if (i === columnsIndex + 1) { columnsData[i].values = columnsData[i - 1].values[value].children } else { columnsData[i].values = columnsData[i - 1].values[0].children } setColumnsSelect((prev) => { prev[i] = 0 return [...prev] }) setCurrentValue((prev) => { prev[i] = columnsData[i].values[0][customFieldNameValue] return prev }) } setColumnsData([...columnsData]) } useEffect(() => { formattedColumns() }, [columns, cascadeLevel]) /** * 多列选择/级联选择 * @param value 选中的要返回的数据 * @param index 选中的位置 * @param columnsIndex 改变的是第几列 0开始 */ const multiColumnChange = (value: Numeric, index: number, columnsIndex: number) => { setCurrentValue((prev) => { prev[columnsIndex] = value return prev }) setColumnsSelect((prev) => { prev[columnsIndex] = index return [...prev] }) if (cascadeLevel) { cascadeFormat(index, columnsIndex) } } const confirm = () => { rest.onConfirm && rest.onConfirm(currentValue) rest.showChange(!show) } const cancel = () => { rest.onCancel && rest.onCancel(currentValue) rest.showChange(!show) } const change = () => { // 组合一下change const backValue: any[] = columnsSelect.reduce((acc, cur, index) => { let _obj = { index: cur, value: currentValue[index] } acc.push(_obj) return acc }, []) if (backValue.length > 0) { rest.onChange && rest.onChange(backValue) } } useEffect(() => { change() }, [columnsSelect]) return ( <> { show && (<View style={styles.bg}> <TouchableWithoutFeedback onPress={() => rest.showChange(false)} ><View style={styles.handel_bg}></View></TouchableWithoutFeedback> <View style={styles.picker}> <View style={styles.picker_title}> <Text onPress={cancel} style={[styles.picker_fontSize, { color: "#cccccc" }]}>{cancelButtonText}</Text> <Text style={[styles.picker_title_content]}>{title}</Text> <Text onPress={confirm} style={[styles.picker_fontSize, { color: "#3170a7" }]}>{confirmButtonText}</Text> </View> <View style={[styles.picker_main, { height: columnHeight * visibleItemCount }]}> { columnsData.map((item: any, index: number) => { return ( <Columns onChange={multiColumnChange} columnIndex={index} visibleItemCount={visibleItemCount} defaultIndex={item.defaultIndex || 0} columnHeight={columnHeight} data={item.values} key={index} customFieldName={customFieldName} cascadeLevel={cascadeLevel} ></Columns> ) }) } {/* <View pointerEvents="none" style={[styles.picker_frame, { height: columnHeight, marginTop: -(columnHeight / 2) }]}> </View> */} </View> </View> </View>) } </> ) } const styles = StyleSheet.create({ bg: { width: "100%", height: "100%", flex: 1, justifyContent: "flex-end", position: 'absolute', top: 0, left: 0, alignItems: 'center', backgroundColor: 'rgba(0, 0, 0, .4)', }, handel_bg: { flex: 1, width: '100%', }, picker: { width: "100%", minHeight: 300, // maxHeight: 440, backgroundColor: "#ffffff", borderTopLeftRadius: 10, borderTopRightRadius: 10, }, picker_title: { padding: 8, flexDirection: "row", justifyContent: "space-between", alignItems: "center", }, picker_title_content: { fontSize: 18, }, picker_fontSize: { fontSize: 16, }, picker_main: { width: "100%", flexDirection: "row", alignItems: "flex-start", overflow: "hidden", }, picker_frame: { width: "100%", backgroundColor: "rgba(248,223,112,0.5)", position: "absolute", top: "50%", left: 0, } }) export default Picker