组件支持业务:
- 传入isExpand=true 可以支持,传入展开收起按钮可以显示文本是否展示全部或省略文本
- 传入moreShow=true 可以支持,文本超过行时显示更多按钮,点击更多按钮可以传入点击事件,文本不超过两行时,显示发送按钮,此时点击发送按钮可以传入发送按钮事件
- 如果业务有需求,大于一行和一行后边有交互逻辑,此组件也是可以实现
组件代码:
data.d.ts文件
interface EllipsisProps {
/**
* 必传项,文本内容
* @defaultValue ''
*/
content: string
/**
* 非必传项,默认百分之百
* @defaultValue 100%
*/
width?: number
/**
* 非必传,展开按钮
* @defaultValue ''
*/
customButton?: ReactDOM
/**
* 非必传项,收起按钮
* @defaultValue ''
*/
collapseButton?: ReactDOM
/**
* 默认展示几行
* @defaultValue 2行
*/
rows?: number
/**
* 非必传项,文本的行高
* @defaultValue ''
*/
lineHeight?: number
/**
* 非必传项,文本的字体大小
* @defaultValue ''
*/
fontSize?: number
/**
* 非必传项,文本的字体颜色
* @defaultValue ''
*/
color?: string
/**
* 非必传项,点击之后是否展开全部,默认为true
* @defaultValue true
*/
whetherToExpandAll?: boolean
/**
* 非必传项,点击之后是否展开全部,如果是whetherToExpandAll false 则告知父组件我点击了展开按钮
* @defaultValue true
*/
whetherToExpandClick?: () => void
/**
* 非必传项,点击之后如果不展开全部,则通知父组件,并且告知是否是超过一行 大于一行则为true
* @defaultValue -
*/
whetherToClick?: (val: boolean) => void
/**
* 判断是否显示 发送或更多按钮
* @defaultValue
*/
moreShow?: boolean
/**
* 发送按钮事件
* @defaultValue
*/
shareChat?: () => void
/**
* 控制是否显示展开 收起按钮
* @defaultValue
*/
isExpand?: boolean
/**
* 更多弹窗事件
* @defaultValue
*/
textShow?: () => void
}
export { EllipsisProps }
index.tsx 文件
import { useBoolean, useReactive } from 'ahooks'
import React, { useEffect, useRef } from 'react'
import { EllipsisProps } from './data'
import { ContentArea } from './styled'
const Ellipsis: React.FC<EllipsisProps> = (props) => {
const {
width,
content = '',
customButton,
collapseButton,
rows = 2,
lineHeight = 22,
fontSize = 14,
color = '#262626',
whetherToExpandAll = true,
whetherToExpandClick,
whetherToClick,
moreShow,
shareChat,
textShow,
isExpand,
} = props
const ref = useRef<HTMLDivElement>(null)
// 控制展开收起
const [open, { toggle }] = useBoolean(false)
const state = useReactive({
isShow: false,
})
useEffect(() => {
// 总体高度
const scrollHeight = ref.current?.scrollHeight || 0
// 可视高度
const clientHeight = ref.current?.clientHeight || 0
if (scrollHeight <= clientHeight) {
ref.current?.classList.add('trunk')
} else {
ref.current?.classList.remove('trunk')
}
// 如果不进行展开收起,则初始进入告知父组件是否是超过一行
if (!whetherToExpandAll) {
// 获取元素的行高
const lineHeight = window.getComputedStyle(
ref.current as Element,
null
).lineHeight
state.isShow = scrollHeight <= clientHeight ? false : true
// 转化行高为数字
const initLineHeight = parseInt(lineHeight.split('px')[0])
// 如果行高加上6px 的偏差 小于可视高度的话,呢么表示超过一行
whetherToClick && whetherToClick(initLineHeight + 6 <= clientHeight)
}
}, [ref && ref.current])
// 点击展开收起
const toggles = () => {
if (whetherToExpandAll) {
toggle()
} else {
whetherToExpandClick && whetherToExpandClick()
}
}
return (
<ContentArea
lineHeight={lineHeight}
fontSize={fontSize}
color={color}
rows={!open ? rows : 9999}
width={width ? width + 'px' : '100%'}
content={content}
isShow={state.isShow}
moreShow={moreShow}
>
<div onClick={toggles} className="textord" ref={ref}>
{isExpand && (
<div onClick={toggles} className="expand">
{!open ? customButton : collapseButton}
</div>
)}
<span
style={{ whiteSpace: 'pre-wrap' }}
dangerouslySetInnerHTML={{ __html: content }}
></span>
{moreShow && (
<span
className={state.isShow ? 'more' : 'send'}
onClick={state.isShow ? textShow : shareChat}
>
{state.isShow ? '更多' : '发送'}
</span>
)}
</div>
</ContentArea>
)
}
export default Ellipsis
styled.ts 文件
import styled from 'ns-styled'
const ContentArea = styled.div<{
width: string
rows: number
content: string
lineHeight: number
fontSize: number
color: string
moreShow: boolean | undefined
isShow: boolean
}>`
display: flex;
.textord {
position: relative;
width: ${(p) => p.width};
max-height: ${(p) => p.rows * 22 + 'px'};
line-height: ${(p) => p.lineHeight + 'px'};
font-size: ${(p) => p.fontSize + 'px'};
color: ${(p) => p.color};
overflow: hidden;
&::before {
content: '';
position: absolute;
right: 0;
bottom: 0;
height: calc(100% - 20px);
min-width: 50px;
background-color: #f5f5f5;
}
.expand {
float: right;
clear: both;
height: 20px;
line-height: 20px;
position: relative;
min-width: 37px;
cursor: pointer;
height: 100%;
text-align: right;
div,
span {
display: inline-block;
}
}
.more {
position: absolute;
right: 0;
bottom: 0px;
height: 22px;
cursor: pointer;
&::before {
content: '...';
position: absolute;
line-height: 0px;
height: 6px;
bottom: 5px;
color: #333;
transform: translateX(-15px);
}
}
.send {
font-size: 12px;
color: #0d5dff;
font-weight: 500;
margin-left: 8px;
cursor: pointer;
}
}
.trunk {
.expand,
.more {
display: none;
}
}
`
export { ContentArea }