一、背景介绍
大家好,我是bysking, 废话不多说,直接上干货,实现一个展开收起组件,本期你chen哥直接手摸手实现一个基于css+js的展开收起组件
二、效果展示
- 收起状态
- 展开状态
使用
<MoreText
text={text2}
line={3}
btnRender={({ toggle, isOpen }) => (
<a onClick={() => toggle?.()}>{isOpen ? '收起' : '展开'}</a>
)}
></MoreText>
三、老规矩直接上代码:
3.1 组件目录结构
3.2 more-text/renderBtn/index.tsx
import { ReactNode, useEffect, useState } from 'react';
type typeProps = {
btnRender?: (params: {
isOpen: boolean;
text: string;
toggle: () => void;
}) => ReactNode;
onClickToggle: () => void;
isAll: boolean;
text: string;
refWrap;
};
const RenderBtn = (props: typeProps) => {
const [show, setShow] = useState(false);
const init = () => {
let parentNode = props.refWrap.current;
if (parentNode) {
let scrollHeight = parentNode.scrollHeight;
let offsetHeight = parentNode.offsetHeight;
if (scrollHeight - offsetHeight > 2) {
setShow(true);
} else {
setShow(false);
}
}
};
useEffect(() => {
init();
}, []);
return (
<div
style={{
display: show ? 'block' : 'none',
float: 'right',
clear: 'both',
}}
>
{props.btnRender ? (
props.btnRender?.({
isOpen: props.isAll,
text: props.text,
toggle: props.onClickToggle,
})
) : (
<a
onClick={() => {
props.onClickToggle();
}}
>
{props.isAll ? '收起' : '展开'}
</a>
)}
</div>
);
};
export default RenderBtn;
3.3 more-text/index.less
.more-text-wrap {
overflow: hidden;
text-overflow: ellipsis;
/* stylelint-disable-next-line value-no-vendor-prefix */
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
position: relative;
word-wrap: break-all;
text-align: justify;
white-space: normal;
}
3.4 more-text/index.tsx
import { ReactNode, useEffect, useRef, useState } from 'react';
import './index.less';
import RenderBtn from './renderBtn';
type typeProps = {
text: string;
line?: number;
btnRender?: (params: {
isOpen: boolean;
text: string;
toggle: () => void;
}) => ReactNode;
};
const RenderMoreText = (props: typeProps) => {
const text = props.text;
const [line, setLine] = useState(props.line);
const refWrap = useRef<HTMLDivElement>();
const initStyle = (line: number) => {
let dom = document.querySelector('.more-text-wrap');
if (dom) {
dom.style['-webkit-line-clamp'] = line;
}
};
const isAll = line !== props.line;
const onClickToggle = () => {
let maxLine = 9999;
setLine(isAll ? props.line : maxLine);
};
useEffect(() => {
initStyle(line);
}, [line]);
useEffect(() => {
setLine(props.line);
}, [props.line]);
return (
<div>
<div style={{ display: 'flex' }}>
<div className="more-text-wrap" ref={refWrap}>
<div
style={{
content: '',
height: 'calc(100% - 22px)', // 减去按钮高度
float: 'right',
}}
></div>
<RenderBtn
btnRender={props.btnRender}
isAll={isAll}
text={props.text}
onClickToggle={onClickToggle}
refWrap={refWrap}
/>
{String(text)}
</div>
</div>
</div>
);
};
export default RenderMoreText;
四、回顾用法
import MoreText from './more-text';
<MoreText
text={text2}
line={3}
btnRender={({ toggle, isOpen }) => (
<a onClick={() => toggle?.()}>{isOpen ? '收起' : '展开'}</a>
)}
></MoreText>
看到这里,欢迎点赞收藏加关注走一波,持续更新干货