小程序实现多行文本”全文收起“(Taro+ts版本)

230 阅读2分钟

感谢原文作者的小程序原生版本

juejin.cn/post/707111…

// index.tsx
import './style.css';
import { View, Text } from '@tarojs/components';
import Taro from '@tarojs/taro';
import { FC, useEffect, useState } from 'react';

interface ContentProps {
	content?: string;
	maxLine?: number;
	position?: 'left' | 'right';
	foldable?: boolean;
	onFoldText?: string;
	unFoldText?: string;
	lineHeight?: number;
}

const TextOverflow: FC<ContentProps> = ({
	content,
	maxLine = 1,
	position = 'left',
	foldable = true,
	onFoldText = '展开',
	unFoldText = '收起',
	lineHeight,
}) => {
	const [width, setWidth] = useState<number | null>(null);
	const [onFold, setOnFold] = useState(false);
	const [showFold, setShowFold] = useState(false);
	const [onReady, setOnReady] = useState(false);

	useEffect(() => {
		getNodeClientReact();
		setOnReady(true);
	}, []);

	useEffect(() => {
		if (onReady) {
			getNodeClientReact();
		}
	}, [maxLine, lineHeight]);

	const changeRpxToPx = (rpxInteger: number): number => {
		return (Taro.getSystemInfoSync().windowWidth / 750) * rpxInteger;
	};

	const getNodeClientReact = () => {
		setTimeout(() => checkFold(), 100);
	};

	const checkFold = () => {
		const query = Taro.createSelectorQuery();
		query
			.selectAll('.showArea, .hideArea')
			.boundingClientRect(res => {
				let showFold = res[0].height < res[1].height;
				const lineHeightToPx = changeRpxToPx(lineHeight);
				const showAreaHeight = res[0].height;
				const hideAreaHeight = res[1].height;
				const maxHeight = lineHeightToPx * maxLine;

				if (lineHeight && showAreaHeight <= maxHeight) {
					showFold = hideAreaHeight > maxHeight;
				}

				let onFold = false;
				if (showAreaHeight == hideAreaHeight && showAreaHeight > maxHeight) {
					showFold = true;
					onFold = true;
				}

				setWidth(res[0].width);
				setShowFold(showFold);
				setOnFold(onFold);
			})
			.exec();
	};

	const handleFold = () => {
		setOnFold(!onFold);
	};

	return (
		<View className="content">
			<View
				className={`contentInner content-inner-class showArea ${
					!onFold ? `text-clamp${maxLine}` : ''
				}`}
			>
				{content}
			</View>
			<View className="contentInner content-inner-class hideArea" style={{ width: `${width}px` }}>
				{content}
			</View>
			{showFold && (
				<View className={`foldInner fold-class ${position === 'right' ? 'flex-end' : 'flex'}`}>
					<Text className="fold" onClick={handleFold}>
						{onFold ? unFoldText : onFoldText}
					</Text>
				</View>
			)}
		</View>
	);
};

export default TextOverflow;

// style.css
.content {
	/* background-color: #ffffff; */
	width: 100%;
	position: relative;
	overflow: hidden;
}

.contentInner {
	word-break: break-all;
	width: 100%;
	color: #2f3033;
	font-size: 30rpx;
	line-height: 1.35;
	/* text-align: justify; */
}

.hideArea {
	display: -webkit-box;
	overflow: hidden;
	/* position: fixed;
  top: 100vh;
  left: -100vw; */
	position: absolute;
	top: 0;
	left: 0;
	z-index: -1;
	color: #fff;
}

.foldInner {
	padding-top: 10rpx;
	color: #6676bd;
	font-size: 28rpx;
}

.foldInner .fold {
	cursor: pointer;
}

.text-clamp1 {
	overflow: hidden;
	display: -webkit-box;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 1;
}

.text-clamp2 {
	overflow: hidden;
	display: -webkit-box;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 2;
}

.text-clamp3 {
	overflow: hidden;
	display: -webkit-box;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 3;
}

.text-clamp4 {
	overflow: hidden;
	display: -webkit-box;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 4;
}

.text-clamp5 {
	overflow: hidden;
	display: -webkit-box;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 5;
}

.flex {
	display: -webkit-box;
	display: -webkit-flex;
	display: flex;
}

.flex-center {
	display: -webkit-box;
	display: -webkit-flex;
	display: flex;
	align-items: center;
	justify-content: center;
	-webkit-align-items: center;
	-webkit-justify-content: center;
}

.flex-alignStart {
	display: -webkit-box;
	display: -webkit-flex;
	display: flex;
	align-items: flex-start;
	-webkit-align-items: flex-start;
}

.flex-alignCenter {
	display: -webkit-box;
	display: -webkit-flex;
	display: flex;
	align-items: center;
	-webkit-align-items: center;
}

.flex-alignEnd {
	display: -webkit-box;
	display: -webkit-flex;
	display: flex;
	align-items: flex-end;
	-webkit-align-items: flex-end;
}

.flex-between {
	display: -webkit-box;
	display: -webkit-flex;
	display: flex;
	justify-content: space-between;
	-webkit-justify-content: space-between;
}

.flex-around {
	display: -webkit-box;
	display: -webkit-flex;
	display: flex;
	justify-content: space-around;
	-webkit-justify-content: space-around;
}

.flex-middle {
	display: -webkit-box;
	display: -webkit-flex;
	display: flex;
	justify-content: center;
	-webkit-justify-content: center;
}

.flex-end {
	display: -webkit-box;
	display: -webkit-flex;
	display: flex;
	justify-content: flex-end;
	-webkit-justify-content: flex-end;
}