import React, { useState, useEffect, useRef, RefObject, ForwardRefRenderFunction, } from 'react' import Popup from '@/packages/popup/index.taro' import PickerSlot from './pickerSlot.taro' import useRefs from '@/utils/useRefs' import { useConfig } from '@/packages/configprovider/configprovider.taro' import bem from '@/utils/bem' export interface PickerOption { text: string | number value: string | number disabled?: string children?: PickerOption[] className?: string | number } export interface PickerProps { isVisible: boolean title?: string listData: (PickerOption | PickerOption[])[] defaultValueData?: (number | string)[] className?: '' style?: React.CSSProperties threeDimensional?: boolean swipeDuration: number | string onConfirm?: ( selectedValue: (string | number)[], selectedOptions: PickerOption[] ) => void onClose?: ( selectedValue: (string | number)[], selectedOptions: PickerOption[] ) => void onCloseUpdate?: ( selectedValue: (string | number)[], list: PickerOption[], pickerRef: RefObject ) => void onChange?: ( index: number, value: (string | number)[], selectedOptions: PickerOption[] ) => void } const InternalPicker: ForwardRefRenderFunction> = (props, ref) => { const { locale } = useConfig() const { isVisible, title, listData = [], defaultValueData, onConfirm, onClose, onCloseUpdate, onChange, className, style, threeDimensional, swipeDuration, ...rest } = props const [chooseValueData, setchooseValueData] = useState< Array >([]) // 选择的数据的 value 值, 每一条数据的 value 值 const [columnIndex, setcolumnIndex] = useState(0) // 选中列 const pickerRef = useRef(null) const [refs, setRefs] = useRefs() const [columnsList, setColumnsList] = useState([]) // 格式化后每一列的数据 const b = bem('picker') const isConfirmEvent = useRef(false) // 默认值修改 useEffect(() => { if ( defaultValueData && defaultValueData.length !== 0 && defaultValueData.toString() !== chooseValueData.toString() ) { const data = [...defaultValueData] setchooseValueData(data) setColumnsList(normalListData() as PickerOption[][]) } }, [defaultValueData]) // 选中值进行修改 useEffect(() => { onChange && onChange(columnIndex, chooseValueData, selectedOptions()) if (isConfirmEvent.current) { isConfirmEvent.current = false onConfirm && onConfirm(chooseValueData, selectedOptions()) } }, [chooseValueData]) // 列表格式修改 useEffect(() => { init() }, [listData]) const closeActionSheet = () => { onClose && onClose(chooseValueData, selectedOptions()) onCloseUpdate && onCloseUpdate(chooseValueData, selectedOptions(), pickerRef) } // 点击确定 const confirm = () => { let movings = false refs.forEach((_ref: any) => { if (_ref.moving) movings = true _ref.stopMomentum() }) if (movings) { isConfirmEvent.current = true } else { onConfirm && onConfirm(chooseValueData, selectedOptions()) } onClose && onClose(chooseValueData, selectedOptions()) setTimeout(() => { isConfirmEvent.current = false }, 0) } const selectedOptions = () => { const optins: PickerOption[] = [] columnsList.map((column: PickerOption[], index: number) => { let currOptions = [] currOptions = column.filter( (item) => item.value === chooseValueData[index] ) if (currOptions[0]) { optins.push(currOptions[0]) } else { column[0] && optins.push(column[0]) } return column }) return optins } // 选择每一列的数据 const chooseItem = (option: PickerOption, columnIndex: number) => { if (option && Object.keys(option).length) { // 是否移动后是否与之前有差异 if (chooseValueData[columnIndex] !== option.value) { if (columnsType() === 'cascade') { chooseValueData[columnIndex] = option.value ? option.value : '' setchooseValueData([...chooseValueData]) let index = columnIndex let cursor = option while (cursor && cursor.children && cursor.children[0]) { chooseValueData[index + 1] = cursor.children[0].value setchooseValueData([...chooseValueData]) index++ const cc = cursor.children[0] cursor = cc } // 当前改变列的下一列 children 值为空 if (cursor && cursor.children) { chooseValueData[index + 1] = '' setchooseValueData([...chooseValueData]) } setColumnsList(normalListData() as PickerOption[][]) } else { setchooseValueData((data) => { const cdata = [...data] cdata[columnIndex] = Object.prototype.hasOwnProperty.call( option, 'value' ) ? option.value : '' return cdata }) } setcolumnIndex(columnIndex) } } } // 传入的数据格式化 const normalListData = () => { const type = columnsType() switch (type) { case 'multiple': return listData case 'cascade': // 级联数据处理 return formatCascade(listData as PickerOption[], chooseValueData) default: return [listData] } } // 每一列的类型 const columnsType = () => { const firstColumn: PickerOption | PickerOption[] = listData[0] if (firstColumn) { if (Array.isArray(firstColumn)) { return 'multiple' } if ('children' in firstColumn) { return 'cascade' } } return 'single' } // 级联数据格式化 const formatCascade = ( columns: PickerOption[], defaultValues: (number | string)[] ) => { const formatted: PickerOption[][] = [] let cursor: PickerOption = { text: '', value: '', children: columns, } let columnIndex = 0 while (cursor && cursor.children) { const options: PickerOption[] = cursor.children const value = defaultValues[columnIndex] let index = options.findIndex( (columnItem) => columnItem.value === value ) if (index === -1) index = 0 cursor = cursor.children[index] columnIndex++ formatted.push(options) } return formatted } const init = () => { const data: (string | number)[] = [] const normalData: PickerOption[][] = normalListData() as PickerOption[][] setColumnsList(normalData) normalData.length > 0 && normalData.map((item) => { item[0] && data.push(item[0].value) return item }) if (!defaultValueData && chooseValueData.length === 0) { setchooseValueData([...data]) } } const renderToolbar = () => { return (
closeActionSheet()}> {locale.cancel}
{title || ''}
{locale.confirm}
) } return ( { closeActionSheet() }} >
{renderToolbar()}
{columnsList?.map((item, index) => { return ( chooseItem(value, index) } swipeDuration={swipeDuration} key={index} keyIndex={index} itemShow={isVisible} /> ) })}
) } const Picker = React.forwardRef>(InternalPicker) export default Picker