自己封装了Ellipsis组件 基于react+taro,以下是实现代码,分为JSX和CSS文件
JSX代码如下:
import { FC, Fragment, JSX, useState } from 'react';
import { Image, StandardProps, Text, View } from '@tarojs/components';
import iconDropDown from '@/assets/icons/icon-dorpdown-primary.svg';
import useBoundingClientRect from '@/hooks/useBoundingClientRect';
import './index.less';
interface EllipsisProps {
rows?: number;
/**
* 收起节点
*/
foldRender?: JSX.Element;
/**
* 是否显示收取按钮
*/
showFold?: boolean;
/**
* 展开节点
*/
unfoldRender?: JSX.Element;
/**
* 是否显示展开按钮
*/
showUnfold?: boolean;
onChange?: (val: boolean) => void;
}
const Ellipsis: FC<EllipsisProps & StandardProps> = ({
rows = 1,
children,
className,
showUnfold,
unfoldRender,
}) => {
const [show, setShow] = useState(false);
const [rectAssist] = useBoundingClientRect('#rectAssist', [children]);
const [rectActual] = useBoundingClientRect('#rectActual', [children]);
const style = {
lineClamp: rows,
webkitLineClamp: rows,
};
const showMoreBtn =
!show &&
showUnfold &&
rectActual?.height &&
rectAssist?.height &&
Number(rectActual?.height) !== Number(rectAssist?.height);
return (
<Fragment>
<View
style={{ position: 'absolute', left: 0, top: -999999, opacity: 0 }}
className={className}
id="rectAssist"
>
{children}
</View>
<View
className={`lineClamp__1 ${className}`}
style={!show ? style : { display: 'block' }}
id="rectActual"
>
{children}
{!!showMoreBtn && (
<View className="unfold-wrap" id="unfoldWrap" onClick={() => setShow(true)}>
{unfoldRender || (
<View className="unfold-btn">
<Text>查看更多</Text>
<Image src={iconDropDown} />
</View>
)}
</View>
)}
</View>
</Fragment>
);
};
export default Ellipsis;
其中useBoundingClientRect 是自定义的hook,代码如下
import React, { useEffect, useState } from 'react';
import Taro, { NodesRef } from '@tarojs/taro';
const useBoundingClientRect = (
selector: string,
deps?: React.DependencyList,
): [rect: NodesRef.BoundingClientRectCallbackResult | undefined] => {
const [rect, setRect] = useState<
NodesRef.BoundingClientRectCallbackResult | NodesRef.BoundingClientRectCallbackResult[]
>();
useEffect(() => {
Taro.nextTick(() => {
Taro.createSelectorQuery()
.select(selector)
.boundingClientRect((respRect) => {
setRect(respRect);
})
.exec();
});
}, [...(deps || [])]);
return [rect as any];
};
export default useBoundingClientRect;
Css代码如下,目前在项目中使用less预编译处理器
.lineClamp(@row) {
display: -webkit-box;
overflow: hidden;
line-clamp: @row;
-webkit-line-clamp: @row;
-webkit-box-orient: vertical;
position: relative;
}
.lineClamp__1 {
.lineClamp(1);
&::after {
color: red;
position: absolute;
right: 0;
bottom: 5px;
}
}
.lineClamp__2 {
.lineClamp(2);
}
.lineClamp__3 {
.lineClamp(3);
}
.unfold-wrap {
position: absolute;
right: 0;
bottom: 0;
display: flex;
background: linear-gradient(to left, #fff, #fff, #fff, rgba(255, 255, 255, 0.4));
}
.unfold-btn {
display: flex;
flex-direction: row;
align-items: center;
min-width: 32px;
padding: 4px 10px 4px 30px;
line-height: 1;
text {
color: #b89962;
font-size: 12px;
font-style: normal;
font-weight: 400;
line-height: 12px; /* 100% */
}
image {
width: 13px;
height: 12px;
}
}
效果如下: