vue3 实现文本内容超过N行折叠并显示“...展开”组件

news2024/11/17 14:30:44

1. 实现效果

在这里插入图片描述
在这里插入图片描述

组件内文字样式取决与外侧定义
组件大小发生变化时,文本仍可以省略到指定行数
文本不超过时, 无展开,收起按钮
传入文本发生改变后, 组件展示新的文本

2. 代码

文件名TextEllipsis.vue

<template>
	<div ref="compRef" class="wq-text-ellipsis">
		<div v-if="!isExpanded" class="ellipsis-content">
			<span>{{ truncatedText }}</span>
			<slot v-if="textOver" name="ellipsis">
				<span>{{ ellipsis }}</span>
			</slot>
			<span v-if="textOver" class="show-more" @click="toggleExpand">
				<slot name="more">
					{{ moreText }}
				</slot>
			</span>
		</div>
		<div v-else class="full-content">
			<span>{{ fullText }}</span>
			<span class="show-less" @click="toggleExpand">
				<slot name="less">
					{{ lessText }}
				</slot>
			</span>
		</div>
	</div>
</template>

<script setup lang="ts">
import { computed, reactive, ref, watch, nextTick } from 'vue';
import { useResizeObserver } from '@vueuse/core';
import { debounce } from 'lodash';

type Prop = {
	text?: string;
	maxLines?: number;
	// 省略显示
	ellipsis?: string;
	moreText?: string;
	lessText?: string;
};

// 定义 props
const props = withDefaults(defineProps<Prop>(), {
	maxLines: 3,
	text: '',
	ellipsis: '...',
	moreText: '展开',
	lessText: '收起',
});

const compRef = ref<HTMLElement>();

// 定义是否展开的状态
const isExpanded = ref(false);

// 定义展开和收起的方法
const toggleExpand = () => {
	isExpanded.value = !isExpanded.value;
};

// 计算截断后的文本
const truncatedText = ref(props.text);

// 定义完整的文本
const fullText = computed<string>(() => props.text);
// 判断是否超过限制行数
const textOver = computed(() => truncatedText.value !== fullText.value);

watch(
	fullText,
	(newValue) => {
		truncatedText.value = fullText.value;
		isExpanded.value = false;
	},
	{
		immediate: true,
	}
);

// 判断是否超过限制行数
const isOver = () => {
	const { height, lineHeight } = getComputedStyle(compRef.value as Element);
	return parseFloat(height) > props.maxLines * parseFloat(lineHeight);
};

// 对字符串进行二分, 直到 找到一个合适的截断位置
const refresh = async () => {
	// if (!isOver()) return;
	let left = 0;
	let right = props.text.length;
	while (left <= right) {
		const mid = Math.floor((left + right) / 2);
		truncatedText.value = props.text.slice(0, mid);
		await nextTick(() => {
			if (isOver()) {
				right = mid - 1;
			} else {
				left = mid + 1;
			}
		});
	}
	truncatedText.value = props.text.slice(0, left - 1);
};

const init = () => {
	if (!isExpanded.value) refresh();
};
// 对init 进行防抖
const debounceInit = debounce(init, 50);
useResizeObserver(compRef, () => {
	debounceInit();
});
</script>

<style lang="scss" scoped>
.wq-text-ellipsis {
	position: relative;
	white-space: normal;
	word-break: break-all;

	.show-more,
	.show-less {
		//float: right;
		cursor: pointer;
		color: lightblue;
		margin-left: 2px;
	}

	.ellipsis-content {
		position: relative;
	}
}
</style>

这里使用到了两个外部库, 分别用于监听, 和防抖, 若没哟引入这两个库可自行封装
debounce函数封装: js之防抖函数
useResizeObserver hook封装: 这个参考第二部分的文件ResizeObserverStore.ts这里 <-可以直接跳转到指定位置

3. 使用说明

代码样例

<div class="mw6">
	<text-ellipsis :max-lines="3" :text="textContent"></text-ellipsis>
</div>

prop参数

name类型说明默认值
textstring内容“”
maxLinesnumber最大行数3
ellipsisstring省略时显示“…”
moreTextstring展示按钮文字“展示”
lessTextstring收起按钮文字“收起”

slot

name说明
ellipsis省略时尾部元素
more省略时按钮元素
less展开时按钮元素

4. 原理说明

主要原理利用二分法, 对字符串进行恰当的截取

// 对字符串进行二分, 直到 找到一个合适的截断位置
const refresh = async () => {
	let left = 0;
	let right = props.text.length;
	// left > right 时为截取合理位置
	while (left <= right) {
		const mid = Math.floor((left + right) / 2);
		truncatedText.value = props.text.slice(0, mid);
		// 下一次刷新后判断是否截取合理
		await nextTick(() => {
			// isOver()函数用来判断行数是否合理
			if (isOver()) {
				// 实际行数超过理想行数就切掉
				right = mid - 1;
			} else {
				// 行数符合理想行数,就得寸进尺, 向更合理出发
				left = mid + 1;
			}
		});
	}
	// 获取到合理位置后进行最后一次截取
	truncatedText.value = props.text.slice(0, left - 1);
};

// 判断是否超过限制行数
const isOver = () => {
	const { height, lineHeight } = getComputedStyle(compRef.value as Element);
	return parseFloat(height) > props.maxLines * parseFloat(lineHeight);
};

本组件用到了 useResizeObserver, 主要作用是对组件元素进行监听, 当组件大小发生变化时会重新触发字符串截取操作, 并使用节流防止截取操作频繁触发

最后

如果在使用过程中出现了问题, 或者组件有没靠略到的地方, 欢迎评论或留言

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2175752.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

新疆交投路桥桥梁公司:向“新”求“质”,积蓄发展新势能

向“新”求“质”谋发展&#xff0c;“发展新质生产力是推动高质量发展的内在要求和重要着力点&#xff0c;必须继续做好创新这篇大文章&#xff0c;推动新质生产力加快发展”。以新质生产力塑造国企新的核心竞争力成为实现高质量发展的关键内容&#xff0c;既具有重大理论意义…

在传销案件中数据库取证的分步指南

金字塔计划的特点是分层结构&#xff0c;主要由招募新成员的机制驱动。取证部门调查这些方案时&#xff0c;往往依靠数据库记录来分析这种结构。这些记录详细描述了上级和下级之间的关系&#xff0c;使调查人员能够描绘出组织的动态。在本文中&#xff0c;我们将探讨如何利用数…

如何用好通义灵码企业知识库问答能力?

通义灵码企业版&#xff1a;通义灵码企业标准版快速入门_智能编码助手_AI编程_智能编码助手通义灵码(Lingma)-阿里云帮助中心 通义灵码提供了基于企业知识库的问答检索增强的能力&#xff0c;在开发者使用通义灵码 IDE 插件时&#xff0c;可以结合企业知识库内上传的文档、文件…

23款奔驰E300立标升级23P智能辅助驾驶案例分享

《23 款奔驰 E300 立标升级 23P 智能辅助驾驶案例》 在汽车科技不断进步的今天&#xff0c;越来越多的车主开始追求更加智能、安全的驾驶体验。今天&#xff0c;我们就为大家带来一款 23 款奔驰 E300 立标升级 23P 智能辅助驾驶的精彩案例。 这辆 23 款奔驰 E300 立标原本就散…

业务调度 -- 线路单板中继模式

OTN网络中&#xff0c;线路板可以设置为中继模式&#xff0c;作为中继提高系统传输距离。当前设备支持“双向中继”与“单向中继”两种模式&#xff0c;不同的线路板支持其中的一种模式。单向中继与双向中继模式下支持“光中继”或“电中继”。 单向中继 VS. 双向中继 单向中…

DTOF(direct Time-of-Flight,直接飞行时间)

一、基本概念 1.1 定义 dToF&#xff0c;即直接飞行时间&#xff08;direct Time-of-Flight&#xff09;&#xff0c;是一种通过测量光脉冲发射出去并反射回来的时间差来直接计算距离的技术。 TOF应用场景非常多&#xff0c;电子消费品领域有人脸识别&#xff0c;照相机辅助对…

程序员数学 | 数学归纳法

目录 一、数学归纳法是什么二、使用编程来模拟数学归纳法的证明 人类做重复性的劳动没有效率&#xff0c;而计算机却能更快更准确的完成重复性劳动。所以以重复为特点的迭代法在编程中有着⼴泛的应⽤。实际项目中是否可以用不断更新变量值或者缩小搜索的区间范围的方法&#xf…

AniJS:无需编程的动画解决方案

前言 在网页设计中&#xff0c;动画效果能够显著提升用户体验&#xff0c;但传统的动画实现往往需要复杂的 JavaScript 代码。 AniJS 库的出现&#xff0c;为设计师和开发者带来了一种全新的动画实现方式&#xff0c;它通过简单的 HTML 属性就能创建出令人惊叹的动画效果。 介…

HTML5+JavaScript绘制闪烁的网格错觉

HTML5JavaScript绘制闪烁的网格错觉 闪烁的网格错觉&#xff08;scintillating grid illusion&#xff09;是一种视觉错觉&#xff0c;通过简单的黑白方格网格和少量的精心设计&#xff0c;能够使人眼前出现动态变化的效果。 闪烁的栅格错觉&#xff0c;是一种经典的视觉错觉…

柯桥小语种学习英语口语培训|被点名时,中文喊“到”,那英文喊什么?

"今日体育课&#xff0c;张老师准时点名。阳光下&#xff0c;同学们精神抖擞&#xff0c;一一应答到。课堂氛围活跃&#xff0c;准备充分&#xff0c;期待精彩训练。"被点名时&#xff0c;中文喊“到”&#xff0c;那英文喊什么&#xff1f; “到”用英语怎么说&…

在WPF中实现多语言切换的四种方式

在WPF中有多种方式可以实现多语言&#xff0c;这里提供几种常用的方式。 一、使用XML实现多语言切换 使用XML实现多语言的思路就是使用XML作为绑定的数据源。主要用到XmlDataProvider类. 使用XmlDataProvider.Source属性指定XML文件的路径或通过XmlDataProvider.Document指定…

5G NR 协议规范表(对应3GPP 协议编号)

文章目录 5G NR 协议规范表&#xff08;对应3GPP 协议编号&#xff09;5G 架构相关协议5G 新空口相关协议无线接入网相关协议终端相关协议 5G NR 协议规范表&#xff08;对应3GPP 协议编号&#xff09; 5G 架构相关协议 5G 新空口相关协议 无线接入网相关协议 终端相关协议

怎么将其他内容与表单组合成二维码?扫码查看内容填写数据的制作技巧

怎么将视频、图片、文字等内容和表单组合生成二维码&#xff1f;现在用二维码来制作表单收集用户数据是一种很常见的方式&#xff0c;将问题做成表单生成二维码&#xff0c;其他人只需要扫码就能够根据问题来填写自己的反馈信息&#xff0c;更加的简单方便。 那么需要让扫码者…

通用型pdf合并工具,分享7款简单易学的pdf处理软件,日常电脑必备!

日常学习和工作中&#xff0c;我们难免会遇到需要编辑pdf文件的情况。熟悉pdf格式文档的小伙伴都知道&#xff0c;pdf不易于编辑&#xff0c;需要借助专业的pdf编辑软件才能实现。现在pdf编辑、pdf转word、pdf合并、pdf拆分等功能都可以轻松实现。尽管如此&#xff0c;也有不少…

服装品牌小程序展示承载服务

服装大小品牌众多&#xff0c;还包括多区域的门店商家合作批发、咨询等&#xff0c;品牌或经销商想要获得更多生意&#xff0c;线上渠道往往是必备的&#xff0c;品牌宣传、获客转化及持续的信息干货输出等。 线上渠道多样化&#xff0c;尤其是微信、百度、抖音、快手等平台聚…

获取 Jupyter Notebook IPython kernel 在电脑中的目录位置

获取 Jupyter Notebook IPython kernel 在电脑中的目录位置 正文 正文 在 VS code 的 terminal 中或者 Windows 的命令行中使用如下代码即可。 ipython locate运行后得到如下结果&#xff1a; 如图所示&#xff0c;我们获取到了 ipython 的位置。 如果大家觉得有用&#xf…

Arthas redefine(加载外部的.class文件,redefine到JVM里 )

文章目录 二、命令列表2.2 class/classloader相关命令2.2.3 redefine&#xff08;加载外部的.class文件&#xff0c;redefine到JVM里 &#xff09;举例1&#xff1a;加载新的代码&#xff0c;jad/mc 命令使用举例2&#xff1a;上传 .class 文件到服务器的技巧 二、命令列表 2.…

童装购买系统小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;商家管理&#xff0c;商品分类管理&#xff0c;尺码信息管理&#xff0c;款式信息管理&#xff0c;商品信息管理&#xff0c;在线咨询管理&#xff0c;系统管理 微信端账号功能包…

基于php摄影门户网站

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目…

多输入多输出预测 | NGO-BP北方苍鹰算法优化BP神经网络多输入多输出预测(Matlab)

多输入多输出预测 | NGO-BP北方苍鹰算法优化BP神经网络多输入多输出预测&#xff08;Matlab&#xff09; 目录 多输入多输出预测 | NGO-BP北方苍鹰算法优化BP神经网络多输入多输出预测&#xff08;Matlab&#xff09;预测效果基本介绍程序设计往期精彩参考资料 预测效果 基本介…