taro3.x: Picker优化使用
定义单个Picker选项组件:
import React, { useEffect, useState } from 'react' import { View, PickerView, PickerViewColumn } from '@tarojs/components' import classnames from 'classnames' import findIndex from 'lodash/findIndex' import './index.scss' export interface IPicker { item: any, //选项对象 name: string //实例picker标识 show: boolean //显示picker list: any[] //picker列表 } export const INIT_PICKER: IPicker = { item: {}, name: '', show: false, list: [] } interface IProps extends IPicker { onConfirm: (any) => void } const CustomPicker = (props: IProps) => { const { item, list, show, onConfirm } = props const [current, setCurrent] = useState<any>({}) useEffect(() => { //同一个生成过程需要setTimeout setTimeout(() => { if (item.index) { // 是否设置过index setCurrent(item) } else { //没有设置过index,在列表中找到当前的项的index const index = findIndex(list, { name: item.name }) setCurrent({ ...item, index }) } }, 0); }, [item]) const handleChange = (e: any) => { const index = e.detail.value[0] setCurrent({ ...list[index], index }) } const handleConfirm = (isConfirm: boolean) => { if (isConfirm) { onConfirm(current.index ? current : list[0]) } else { onConfirm(null)
设置回之前的index } } return ( <View className={classnames('picker', show && 'show')}> <View className="mask show" onClick={() => onConfirm(null)}></View> <View className="picker-content"> <View className="dialog-header"> <View className="dialog-button cancel" onClick={() => handleConfirm(false)}>取消</View> <View className="dialog-button" onClick={() => handleConfirm(true)}>确定</View> </View> <PickerView className='picker-view-wrap' onChange={handleChange} value={[current.index]}><!--设置当前选择项--> <PickerViewColumn> { list.map((item: any, index: number) => { return <View className="picker-item" key={index}>{item.name}</View> }) } </PickerViewColumn> </PickerView> </View> </View> ) } export default CustomPicker
样式:
.picker { position: absolute; top: 0; bottom: 0; width: 100%; height: 100vh; visibility: hidden; &.show { visibility: visible; .picker-content { transform: translateY(0); transition: all 0.4s ease; } } .picker-content { position: fixed; bottom: 0; width: 100%; background-color: $white; transform: translateY(150%); transition: all 0.4s ease; z-index: 99; .dialog-header { width: 100%; background: $bg-color; display: flex; justify-content: space-between; align-items: center; .dialog-button { display: inline-block; text-align: center; font-size: 32px; color: $primary-color; padding: 30px; &.cancel { color: $text-color; } } } .picker-view-wrap { width: 100%; height: 400px; .picker-item { line-height: 70px; font-size: 36px; text-align: center; } } } }
使用:
const customPicker = () => useMemo(() => { return ( <CustomPicker key={picker.name} item={picker.item} name={picker.name} show={picker.show} list={picker.list} onConfirm={handlePickerConfirm} ></CustomPicker> ) }, [picker])//根据picker项变动更新picker组件触发useEffect更新当前item项
相关方法:
const handlePickerConfirm = (item: any) => { if (item) { setPickerValue({ ...pickerValue, [picker.name]: item }) } setPicker({ ...picker, show: false, }) } const selectPicker = (name: string) => { setPicker({ name, show: true, list: pickerObject[name], item: pickerValue[name].value ? pickerValue[name] : INIT_PICKER_VALUE[name] }) }
picker项:
const renderValue = (value: string) => { return value ? <Text className="input-text">{value}</Text> : <Text className="input-placeholder">请选择</Text> } const renderPicker = (name: string, text: string) => ( <View className="calc-item" onClick={() => selectPicker(name)}> <View className="item-label">{text}</View> <View className="item-input"> {renderValue(pickerValue[name].name)} </View> <View className="item-icon"> <Text className="iconfont iconarrow-right-bold"></Text> </View> </View> )
初始化pickerValue:
const INIT_PICKER_VALUE = { loadRatio: {}, fundPeriod: { name: '基金', value: '200' } }
const [picker, setPicker] = useState<IPicker>(INIT_PICKER)
const [pickerValue, setPickerValue] = useState<any>(INIT_PICKER_VALUE)