✨ feat(toolTip组件): 新增toolTip组件
This commit is contained in:
parent
3199628d4f
commit
3837c07dd8
@ -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'
|
||||||
|
50
src/components/toolTips/index.module.scss
Normal file
50
src/components/toolTips/index.module.scss
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
216
src/components/toolTips/index.tsx
Normal file
216
src/components/toolTips/index.tsx
Normal 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
|
@ -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>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user