feat(toolTip组件): 新增toolTip组件

This commit is contained in:
xuan 2022-10-13 17:41:14 +08:00
parent 3199628d4f
commit 3837c07dd8
4 changed files with 277 additions and 4 deletions

View File

@ -1,3 +1,7 @@
/**
* position: relative;
*/
import { View, Text } from '@tarojs/components' import { View, Text } from '@tarojs/components'
import { useEffect, useMemo, useRef, useState } from 'react' import { useEffect, useMemo, useRef, useState } from 'react'
import styles from './index.module.scss' import styles from './index.module.scss'

View File

@ -0,0 +1,50 @@
.mark {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: transparent;
}
.tooltip {
&-container{
position: relative;
}
position: absolute;
left: 0;
top: 0;
user-select: text;
color: white;
&-inner {
position: absolute;
background-color: #333333;
font-size: $font_size;
box-shadow: 0 0 30px 0 rgba(51, 51, 51, 0.2);
border-radius: 8px;
&-content {
padding: 8px 12px;
white-space: nowrap;
}
}
&-hidden {
display: none;
}
}
.arrowIcon {
position: absolute;
display: flex;
justify-content: center;
align-items: center;
&-top {
transform: rotate(0deg);
}
&-left {
transform: rotate(270deg);
}
&-right {
transform: rotate(90deg);
}
&-bottom {
transform: rotate(180deg);
}
}

View File

@ -0,0 +1,216 @@
import { View } from '@tarojs/components'
import Taro from '@tarojs/taro'
import classNames from 'classnames'
import { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react'
import IconFont from '../iconfont/iconfont'
import styles from './index.module.scss'
const SystemWidth = Taro.getSystemInfoSync().windowWidth
const arrowSize = 32
// 由于taro自动把px编译成rpx所以这里需要把单位处理一下 转成真正的px
const convertPx = (px: number) => {
const realPx = (px / 750) * SystemWidth
return realPx
}
type Placement = 'top' | 'right' | 'bottom' | 'left'
interface ToolTipEvent {
onVisibleChange?: (visible?: boolean) => void
}
interface ToolTipPropsType extends ToolTipEvent {
defaultVisible?: boolean
content: React.ReactNode
placement?: Placement
children?: React.ReactNode
customClassName?: string
customStyle?: React.CSSProperties
customContentStyle?: React.CSSProperties
}
interface ToolTipRef {
show: () => void
hide: () => void
visible: boolean
}
const popoverStyle = {
color: '#333333',
}
const ToolTip = forwardRef<ToolTipRef, ToolTipPropsType>((props, ref) => {
const { placement = 'top', defaultVisible = false, onVisibleChange, children, content = '请填入提示信息', customClassName, customStyle, customContentStyle } = props
if (!content){
throw new Error('tooltip: content 不能为空')
}
const [visible, setVisible] = useState(defaultVisible)
const onVisibleChangeRef = useRef(onVisibleChange)
onVisibleChangeRef.current = onVisibleChange
// 暴露方法给外部
useImperativeHandle(
ref,
() => {
return {
show: () => setVisible(true),
hide: () => setVisible(false),
visible,
}
},
[visible],
)
const handleClick = useCallback(() => {
setVisible(v => {
onVisibleChangeRef.current?.(!v)
return !v
})
}, [])
const handleClickMark = useCallback(() => {
setVisible(false)
onVisibleChangeRef.current?.(false)
}, [])
const getArrowSide = useMemo(() => {
const side = placement.split('-')[0] as string // placement = 'top-start' 取 'top'
const arrowSide = {
top: 'bottom',
right: 'left',
bottom: 'top',
left: 'right',
}[side] as string
return arrowSide
}, [placement])
const [childrenRect, setChildrenRect] = useState<any>({})
const childrenRectRef = useRef(childrenRect)
childrenRectRef.current = childrenRect
const [viewport, setViewport] = useState<any>({})
const viewportRef = useRef(viewport)
viewportRef.current = viewport
useEffect(() => {
console.log('useLayoutEffect')
const query = Taro.createSelectorQuery()
query.select('#children').boundingClientRect()
query.selectViewport().scrollOffset()
query.exec(res => {
console.log(res[0])
console.log(res[1])
setChildrenRect(res[0])
childrenRectRef.current = res[0]
setViewport(res[1])
viewportRef.current = res[1]
})
}, [])
// 箭头 坐标
const arrowCoords = useMemo(() => {
console.log('getArrowSide==>', getArrowSide, childrenRectRef.current)
switch (getArrowSide) {
case 'bottom': // 下箭头
return {
left: childrenRectRef.current.width / 2 - convertPx(arrowSize) / 2,
top: -convertPx(arrowSize),
right: '',
bottom: '',
}
case 'left': // 左箭头
return {
left: childrenRectRef.current.width,
right: '',
top: childrenRectRef.current.height / 2 - convertPx(arrowSize) / 2,
bottom: '',
}
case 'top': // 上箭头
return {
left: childrenRectRef.current.width / 2 - convertPx(arrowSize) / 2,
right: '',
top: childrenRectRef.current.height,
bottom: '',
}
case 'right': // 右箭头
return {
left: -convertPx(arrowSize),
right: '',
top: childrenRectRef.current.height / 2 - convertPx(arrowSize) / 2,
bottom: '',
}
}
}, [getArrowSide, childrenRectRef.current])
// content 坐标
const contentCoords = useMemo(() => {
switch (getArrowSide) {
case 'bottom': // 下箭头
return {
left: 0,
top: '',
right: '',
bottom: convertPx(arrowSize) - 5,
}
case 'left': // 左箭头
return {
left: childrenRectRef.current.width + convertPx(arrowSize) - 5,
top: 0,
right: '',
bottom: '',
}
case 'top': // 上箭头
return {
left: 0,
top: childrenRectRef.current.height + convertPx(arrowSize) - 5,
right: '',
bottom: '',
}
case 'right': // 右箭头
return {
left: '',
top: 0,
right: convertPx(arrowSize) - 5,
bottom: '',
}
}
}, [getArrowSide, childrenRectRef.current])
const ContentComponent = useMemo(() => {
console.log('执行完')
return (
<View className={classNames(styles.tooltip, visible ? '' : styles['tooltip-hidden'], customClassName)} style={customStyle}>
{/* 箭头 */}
<View className={classNames(styles.arrowIcon, styles[`arrowIcon-${getArrowSide}`])} style={arrowCoords}>
<IconFont name='icon-shouqi1' size={arrowSize} color={popoverStyle.color}></IconFont>
</View>
{/* content */}
<View className={styles['tooltip-inner']} id='content' style={{ ...contentCoords, ...customContentStyle }}>
<View className={styles['tooltip-inner-content']}>{content}</View>
</View>
</View>
)
}, [content, getArrowSide, visible, arrowCoords, contentCoords])
return (
<>
{/* 遮罩层 */}
<View className={classNames(styles.mark, visible ? '' : styles['tooltip-hidden'])} onClick={handleClickMark}></View>
<View className={styles['tooltip-container']}>
<View onClick={handleClick} id='children'>
{children}
</View>
{ContentComponent}
</View>
</>
)
})
export default ToolTip

View File

@ -10,6 +10,7 @@ import SelectSaleType from '@/components/SelectSaleType'
import SelectTimePicker, { ChangedValue } from '@/components/SelectTimePicker' import SelectTimePicker, { ChangedValue } from '@/components/SelectTimePicker'
import Table from '@/components/table' import Table from '@/components/table'
import TimePicker from '@/components/timePicker' import TimePicker from '@/components/timePicker'
import ToolTip from '@/components/toolTips'
import { View, Text } from '@tarojs/components' import { View, Text } from '@tarojs/components'
import classnames from 'classnames' import classnames from 'classnames'
import dayjs from 'dayjs' import dayjs from 'dayjs'
@ -177,10 +178,12 @@ const saleStatistic = () => {
</View> </View>
<Divider direction='horizontal' customStyles={{ margin: '30rpx 0' }}></Divider> <Divider direction='horizontal' customStyles={{ margin: '30rpx 0' }}></Divider>
<View className={styles.totalSummary}> <View className={styles.totalSummary}>
<View className='flex-row items-center'> <ToolTip placement='top' content='请填入提示信息'>
<Text className={styles['totalSummary--title']}></Text> <View className='flex-row items-center'>
<Iconfont name='icon-tishi' size={36} color='#707070'></Iconfont> <Text className={styles['totalSummary--title']}></Text>
</View> <Iconfont name='icon-tishi' size={36} color='#707070'></Iconfont>
</View>
</ToolTip>
<View className={styles['totalSummary--current']}>3425</View> <View className={styles['totalSummary--current']}>3425</View>
<View className={styles['totalSummary--totalNum']}>432423</View> <View className={styles['totalSummary--totalNum']}>432423</View>
</View> </View>