✨ 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 { useEffect, useMemo, useRef, useState } from 'react'
|
||||
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 Table from '@/components/table'
|
||||
import TimePicker from '@/components/timePicker'
|
||||
import ToolTip from '@/components/toolTips'
|
||||
import { View, Text } from '@tarojs/components'
|
||||
import classnames from 'classnames'
|
||||
import dayjs from 'dayjs'
|
||||
@ -177,10 +178,12 @@ const saleStatistic = () => {
|
||||
</View>
|
||||
<Divider direction='horizontal' customStyles={{ margin: '30rpx 0' }}></Divider>
|
||||
<View className={styles.totalSummary}>
|
||||
<View className='flex-row items-center'>
|
||||
<Text className={styles['totalSummary--title']}>订单总数</Text>
|
||||
<Iconfont name='icon-tishi' size={36} color='#707070'></Iconfont>
|
||||
</View>
|
||||
<ToolTip placement='top' content='请填入提示信息'>
|
||||
<View className='flex-row items-center'>
|
||||
<Text className={styles['totalSummary--title']}>订单总数</Text>
|
||||
<Iconfont name='icon-tishi' size={36} color='#707070'></Iconfont>
|
||||
</View>
|
||||
</ToolTip>
|
||||
<View className={styles['totalSummary--current']}>3425</View>
|
||||
<View className={styles['totalSummary--totalNum']}>(共432423匹)</View>
|
||||
</View>
|
||||
|
Loading…
x
Reference in New Issue
Block a user