2022-09-30 10:00:08 +08:00

123 lines
3.7 KiB
TypeScript

import { View, Text } from '@tarojs/components'
import { useEffect, useMemo, useRef, useState } from 'react'
import styles from './index.module.scss'
import Iconfont from '../iconfont/iconfont'
import Popup from '../popup'
import Cell from '../cell'
import Taro from '@tarojs/taro'
// 弹窗选择向上弹窗还是向下弹窗
type Direction = 'up' | 'down'
// 配置 菜单可选项
export type DropDownOptions = {
text: string
value: number
}
interface DropDownEvent {
change?: (value: DropDownOptions['value']) => void // value 变化时触发
}
interface PropsType extends DropDownEvent {
direction?: Direction
options?: DropDownOptions[]
title?: string
value: number | string // 当前选中的值
children?: React.ReactNode
activeColor?: string
showOverlay?: boolean
customClassName?: string
customStyle?: React.CSSProperties
}
export default (props: PropsType) => {
const { children, direction = 'down', title = '', value, options = [], change, activeColor, showOverlay = true } = props
const [showPopup, setShowPopup] = useState(false)
const handleClickOption = (value: DropDownOptions['value']) => {
change?.(value)
}
const [text, setText] = useState(options?.[0]?.text || '')
const defaultOptions = useMemo(() => {
const currentValue = value
return options?.map(({ text, value }) => {
currentValue === value && setText(text)
return <Cell title={text} desc='' isLink onClick={() => handleClickOption(value)}></Cell>
})
}, [value])
const getIconName = () => {
if (direction === 'up') {
return showPopup ? 'icon-zhankai1' : 'icon-shouqi1'
}
// down
return showPopup ? 'icon-shouqi1' : 'icon-zhankai1'
}
const handleClickTitle = () => {
setShowPopup(true)
}
const handleClosePopup = () => {
setShowPopup(false)
}
const [overlayOffsetTop, setOverlayOffsetTop] = useState('unset')
// 获取遮罩层的样式
const getOverlayStyle = (): React.CSSProperties => {
return { position: 'absolute', top: 0 }
}
// 获取整个页面的完整高度
const [scrollHeight, setScrollHeight] = useState(0)
useEffect(() => {
const query = Taro.createSelectorQuery()
query.select('#DropDownItem').boundingClientRect()
query.selectViewport().scrollOffset()
query.exec(res => {
console.log('res==>', res)
setScrollHeight(res[1].scrollHeight)
if (direction === 'down') {
setOverlayOffsetTop(res[0].bottom + 'px')
} else {
setOverlayOffsetTop(res[0].top + 'px')
}
})
}, [])
// 获取样式
const getCustomStyle: React.CSSProperties = useMemo(() => {
if (direction === 'up') {
return { position: 'absolute', top: 0, height: overlayOffsetTop }
} else {
return { position: 'absolute', top: overlayOffsetTop, height: `calc(${scrollHeight + 'px'} - ${overlayOffsetTop})` }
}
}, [overlayOffsetTop])
return (
<View className={styles.dropDownItem} id='DropDownItem'>
<View className={styles['dropDownItem--title']} onClick={handleClickTitle}>
<Text className={styles['dropDownItem--title--text']} style={showPopup ? { color: activeColor } : {}}>
{title ? title : text}
</Text>
<Iconfont name={getIconName()} size={20} color={showPopup ? activeColor : '#7f7f7f'}></Iconfont>
</View>
<Popup
onClose={handleClosePopup}
showOverLay={showOverlay}
show={showPopup}
showTitle={false}
safeAreaInsetBottom={false}
customStyle={getCustomStyle}
overlayStyle={getOverlayStyle()}
position={direction === 'down' ? 'top' : 'bottom'}>
{children ? children : <View className={styles.dropDownItemOptions}>{defaultOptions}</View>}
</Popup>
</View>
)
}