TextClamp for Vue3.0(Vue3.0的文本展开收起组件)
呦!大家好,好久没有更新博客了,最近实现了一个一直想自己完成的一个东西,就是文本的展开收起组件,以前项目需要用到,自己实现一个又太繁琐,所以那个时候都是用的别人的轮子,现在自己尝试了一下,居然实现了,所以在这里向各位分享一下。(郑重声明,实现肯定有很多种方法,下面的只是我自己原创的方法,不喜勿喷)代码其实很简单,注释也很详细,具体的实现效果也还是不错的,现在在下面贴一下代码:
npm包的链接在这里:text-clamp-for-vue3 - npm (npmjs.com)
TextClamp.vue
<script setup lang="ts">
import { addListener, removeListener } from 'resize-detector'
import { ref, onMounted, onUnmounted } from 'vue'
import $ from 'jquery'
const props = withDefaults(defineProps<{text: string; // 传入的文本,必传项buttonType?: 'oneLine' | 'tight'; // 展开收起按钮分为:1. oneLine:自身占据单行 2. tight:和文字紧密相邻maxLines?: number; // 设置的显示的行数isExpanded?: boolean; // 展开的状态,true:展开,false:收起
}>(), {buttonType: 'oneLine',isExpanded: false,maxLines: 3
})
const textClampRef = ref<HTMLElement | null>(null) // 最外层div的ref
// const textClampContainerRef = ref<HTMLElement | null>(null) // 该组件放内容的容器的ref
const textRef = ref<HTMLElement | null>(null) // 该组件放文本内容的ref
const toggleButtonRef = ref<HTMLElement | null>(null)
const expanded = ref(props.isExpanded) //本地的expanded状态,先获取一遍属性中的isExpanded状态,然后才能用toggle方法进行修改
const step = ref<number>(200) // 截取文本的位置
// 这个是按钮为单行的模式下的折叠文本的css
const clampClass = ref({'display': '-webkit-box','-webkit-box-orient': 'vertical','-webkit-line-clamp': `${props.maxLines}`,// 这里可以根据给定的行数设置具体的clamp行数,这也是我要将css封装成一个对象的目的'overflow': 'hidden','text-overflow': 'ellipsis'
})
// 往右移动一个步长,注意我在这里将步长设置为了2,因为如果设置为1的时候,出现按钮不能紧密收紧的情况比较频繁,设置为2之后基本就正常了
function moveRight() {step.value = step.value + 2
}
// 往左移动一个步长
function moveLeft() {step.value = step.value - 2
}
/*** 获取一下展开收起按钮的宽度*/
function getButtonWidth() {// 按钮const buttonElement = $('#textRefSpan').next()[0]// 文本容器const textContainer = textClampRef.value// 按钮的宽const buttonWidth = buttonElement.clientWidth// 按钮容器的宽const textContainerWidth = textContainer?.clientWidth// return出去给其他方法用return { buttonWidth, textContainerWidth }
}
/*** ?将文本进行折叠(只在按钮的类型为tight的时候发挥作用)* *具体实现思路:先随便假定一个截取范围,例如我这里给的是[0,200],然后截取完对比下rect的宽度和maxLines,若maxLines < rect.length,则左移;若maxLines > rect.length,则右移;若相等,则调用tightText()收紧文本*/
function clampText(tag?: string) {// 要在expand为false即收起的状态时或者tag为'canClamp'时即’可以折叠‘时才执行这个函数的函数体,这样做的原因是文本有可能在展开的状态下用户调整了浏览器的宽度,这样的话,展开收起按钮可能会因为expand的变化而不断变化,这样体验就差了if (!expanded.value || tag == 'canClamp') {// 先让textRef的内容从0截取到step,step是我随便设置的,设置为200,你也可以设置为其他值,我的想法是先设置为200,然后再调整,然后再逐步收紧textRef.value && (textRef.value.textContent = props.text.slice(0, step.value) + '...')const rects = textRef.value?.getClientRects()if (rects) {console.log('rects:', rects);if (props.maxLines < rects?.length) {moveLeft();} else if (props.maxLines > rects?.length) {moveRight();} else {tightText()return}// 也需要递归调用一下自己,使文本的实际行数和给定的maxLines保持一致clampText();}}
}
/*** 收紧文本,使按钮紧贴文本的省略号*/
function tightText() {// 获取一下按钮和textContainer的宽度const { buttonWidth, textContainerWidth } = getButtonWidth()// 获取一下文本有几行(即有几个矩形)const rects = textRef.value?.getClientRects()// 如果rects或者textContainerWidth都存在的话sif (rects && textContainerWidth) {// 判断一下最后一个矩形的宽度加上按钮的宽度是否小于等于容器的宽度,如果是的话,就直接return,这个时候按钮就会紧贴文本的最右边而不换行(因为这个方法递归了)if ((rects[rects.length - 1].width + buttonWidth <= textContainerWidth) && props.maxLines == rects?.length) {return}// 如果最后一个矩形的宽度加按钮的宽度会大于等于容器宽度,说明这个时候按钮如果放在文本的最末尾就会超出导致换行,所以下面要moveLeft()if (rects[rects.length - 1].width + buttonWidth >= textContainerWidth) {console.log('here:');moveLeft()// 使用moveLeft()往左边移动后,再设置一下文本textRef.value && (textRef.value.textContent = props.text.slice(0, step.value) + '...')} else {// 如果最后一个矩形的宽度加按钮的宽度会小于等于容器宽度,说明这个时候按钮如果放在文本的最末尾不会超出导致换行,但是有可能结尾空很多空间,所以下面要moveRight(),往右收紧一点moveRight()textRef.value && (textRef.value.textContent = props.text.slice(0, step.value) + '...')}// 递归调用一下自己,不断去收紧,前面有return,所以不会爆栈tightText()}
}
/*** 初始处理一下文本*/
function init() {// 当按钮是tight时,什么也不做;若按钮是oneLine时,将显示maxLines那么多行的含省略号的样式加上props.buttonType == 'tight' ? (textRef.value && (textRef.value.textContent = props.text.slice(0, step.value) + '...')) : $('#textRefSpan').css(clampClass.value)// 获取当前文本有多少行const rects = textRef.value?.getClientRects()if (rects) {// 当给定的maxLines的行数要比真正文本的行数还要小时,此时需要进行文本的截取if (props.maxLines <= rects.length) {clampText()} else {// 此时maxLines大于或者等于真正的文本行数,此时无需截取,之前将所有文本显示出来就好/*** !顺带一提,当按钮类型为oneLine时,是直接执行的这个else,因为本函数的开头在按钮为oneLine时为TextRefSpan设置了style,这会导致getClientRects只能取到一个矩形,即使用了css省略后的矩形,此时直接将textRef的内容设置为原文即可,css会自动省略,显示给定的行数*/textRef.value && (textRef.value.textContent = props.text)}}
}/*** 切换展开收起的方法*/
function toggle() {// 当按钮的类型是单行类型时if (props.buttonType == 'oneLine') {// 当前是折叠状态时,一点就变成展开状态if ($('#textRefSpan').attr('style') !== undefined) {$('#textRefSpan').removeAttr('style')} else {// 当前是展开状态,一点变成折叠状态$('#textRefSpan').css(clampClass.value)}expanded.value = !expanded.value} else {// 当按钮的类型是紧密类型时if (!expanded.value) {// 判断,若当前(即点击toggle之前)是收起的状态,那么需要将文本展开,显示未截取的原文本// 此时要将监听去掉,不然在mounted中的监听会让文本又变成省略的状态props.buttonType == 'tight' && removeListener(textClampRef.value as HTMLElement)textRef.value && (textRef.value.textContent = props.text)} else {// 若当前已经是展开了的状态了,那么需要对文本进行截取,调用截取方法clampText('canClamp')}// 切换一下展开收起的状态expanded.value = !expanded.value// 将监听加上props.buttonType == 'tight' && addListener(textClampRef.value as HTMLElement, () => {clampText()})}
}
onMounted(() => {init()// 当按钮的类型是tight时才启动这个监听器if (textClampRef.value && props.buttonType == 'tight') {addListener(textClampRef.value as HTMLElement, () => {clampText()})}
})
onUnmounted(() => {// 卸载的时候取消对textClampRef的监听if (textClampRef.value && props.buttonType == 'tight') {removeListener(textClampRef.value as HTMLElement)}
}
)
</script><template><div ref="textClampRef"><!-- <div ref="textClampContainerRef"> --><span ref="textRef" id="textRefSpan"></span><slot ref="toggleButtonRef" name="textExpandButton" :toggle="toggle" :buttonType="buttonType":isExpanded="expanded"></slot><!-- </div> --></div>
</template>
<style scoped></style>
调用方法看:App.vue
<script setup lang="ts">
import TextClamp from "./components/TextClamp.vue";
import Card from "./components/Card.vue";
import { ref, computed, onMounted } from "vue";
let str ="The ETH upgrade upgrade timeline has never been clear. The end of December last year, as well as June and August this year, are all hazy dates. This time,the core developers have provided a clear date, market confidence has increased, and the voice is loud, and Ethereum has been impacted. There aretwo voices on Ethereum 2.0 in the market, with hundreds of billions ofdollars at stake. The first is to be pessimistic, thinking that theintroduction of 2.0 with cheap gas fees and large processing capacity willallow more projects to settle in Ethereum, and that the expansion of ETH'sdemand would raise the price of ETH.The second option is to remain solidlybearish.Following 2.0, a large number of ETHs were freed, and mass sellingand homogenization rivalry became more intense.";
</script><template><Card><template #banner><img src="./assets/image3.png" /></template><template #description><TextClamp :text="str" :buttonType="'tight'" :maxLines="4"><template #textExpandButton="props"><div v-if="props.buttonType == 'oneLine'" :style="{textAlign: 'left',cursor: 'pointer',display: 'flex',justifyContent: 'flex-end'}"><button @click="props.toggle">{{ props.isExpanded ? "Collapse" : "Expand" }}</button></div><button @click="props.toggle" v-else>{{ props.isExpanded ? "Collapse" : "Expand" }}</button></template></TextClamp></template></Card>
</template><style scoped>
.logo {height: 6em;padding: 1.5em;will-change: filter;
}.logo:hover {filter: drop-shadow(0 0 2em #646cffaa);
}.logo.vue:hover {filter: drop-shadow(0 0 2em #42b883aa);
}
</style>
大家可以自己下载下来跑一下看看:
源码的链接在这里
https://github.com/KBKUN024/TextClamp-for-Vue3.0如果大家有更好的实现,或者对代码的有什么改进的话,非常欢迎提PR,如果对你有用,麻烦你给我一个star吧哈哈。
相关文章:
TextClamp for Vue3.0(Vue3.0的文本展开收起组件)
呦!大家好,好久没有更新博客了,最近实现了一个一直想自己完成的一个东西,就是文本的展开收起组件,以前项目需要用到,自己实现一个又太繁琐,所以那个时候都是用的别人的轮子,现在自己…...
区间预测 | MATLAB实现VAR向量自回归时间序列区间预测
区间预测 | MATLAB实现VAR向量自回归时间序列区间预测 目录 区间预测 | MATLAB实现VAR向量自回归时间序列区间预测预测效果基本介绍程序设计参考资料预测效果 基本介绍 区间预测 | MATLAB实现VAR向量自回归时间序列区间预测 VAR(Vector Autoregression)模型是一种广泛应用于时…...
在 Windows 上搭建 NTP 服务器
文章目录 一、基础环境二、适用场景三、操作步骤四、常用的NTP服务器五、参考资料 版权声明:本文为博主原创文章,于2023年7月30日首发于CSDN,转载请附上原文出处链接和本声明。本文链接:https://blog.csdn.net/u011046671 一、基础…...
应急响应经典案例-FTP 暴力破解
应急响应经典案例-FTP 暴力破解 应急场景日志分析应急处理措施 应急场景 从昨天开始,网站响应速度变得缓慢,网站服务器登录上去非常卡,重启服务器就能保证一段时间的正常访问,网站响应状态时而飞快时而缓慢,多数时间是…...
41. linux通过yum安装postgresql
文章目录 1.下载安装包2.关闭内置PostgreSQL模块:3.安装postgresql服务:4.初始化postgresql数据库:5.设置开机自启动:6.启动postgresql数据库7.查看postgresql进程8.通过netstat命令或者lsof 监听默认端口54329.使用find命令查找了一下postgresql.conf的配置位置10.修改postgre…...
SpringBoot启动流程及自动配置
SpringBoot启动流程源码: 1、启动SpringBoot启动类SpringbootdemoApplication中的main方法。 SpringBootApplication public class SpringbootdemoApplication {public static void main(String[] args) {SpringApplication.run(SpringbootdemoApplication.class, …...
【Linux】进程轻松入门
目录 一, 冯* 诺依曼体系结构 1,存储结构 编辑 二, 操作系统 1,概念 2,设计OS的目的 3,定位 4,如何理解 "管理" 5, 总结 三,进程 1. 概念 那么…...
【使用时空RBF-NN进行非线性系统识别】实现了 RBF、分数 RBF 和时空 RBF 神经网络,用于非线性系统识别研究(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
Tomcat 安装配置教程及成功后,启动失败报错解决方案
解决方案 我的报错原因是因为我的JDK是1.8的而我的Tomcat是10版本的,可能是因为版本原因吧,我重新装了Tomcat 9就可以启动成功了! 简单说下安装的时候需要注意哪些步骤吧 今天我在安装tomcat10的时候,安装成功后,启…...
C#文件操作从入门到精通(2)——查看某个dll中有哪些函数
kernel32.dll中含有ini文件操作使用的函数,我们可以通过VisualStudio自带的dumpbin.exe查看dll所包含的函数,操作步骤如下: 1、找到dumpbin.exe所在的文件夹 我的电脑中安装了VisualStudio2019社区版以及VisualStudio2017Professional,但是我发现VisualStudio2019社区版中…...
二分查找算法(全网最详细代码演示)
二分查找也称 半查找(Binary Search),它时一种效率较高的查找方法。但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字 有序 排列。 注意:使用二分查找的前提是 该数组是有序的。 在实际开…...
draw up a plan
爱情是美好的,却不是唯一的。爱情只是属于个人化的感情。 推荐一篇关于爱情的美文: 在一个小镇上,有一家以制作精美巧克力而闻名的手工巧克力店,名叫“甜蜜之爱”。这家巧克力店是由一位名叫艾玛的年轻女性经营的,她对…...
抖音seo源码开发源代码开发技术分享
一、 抖音SEO源码开发,需要掌握以下技术: 抖音API接口:抖音提供了丰富的API接口,包括用户信息、视频信息、评论信息等。 数据爬取技术:通过抓包分析抖音接口的数据结构,可以使用Python等编程语言编写爬虫程…...
QEMU(Quick Emulator)
QEMU(Quick Emulator)是一款由法布里斯贝拉等人编写的免费的可执行硬件虚拟化的开源托管虚拟机。它可以通过动态的二进制转换模拟CPU,并提供一组设备模型,使它能够运行多种未修改的客户机OS。QEMU还可以为user-level的进程执行CPU…...
Gateway结合nacos(lb://xxx)无效问题
Gateway结合nacos无效 版本如下: com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-discovery:2021.0.1.0 org.springframework.cloud:spring-cloud-starter-gateway:3.1.1 配置如下: server:port: 7000 spring:application:name: springCloudGa…...
NODEJS笔记
全局对象 global/window console.log/info/warn/error/time/timeEnd process.arch/platform/version/env/kill/pid/nextTick Buffer.alloc(5,abcde) String/toString setTimeout/clearTimeout setInterval/clearInterval setImmediate/clearImmediate process.nextTi…...
无涯教程-jQuery - html( )方法函数
html(val)方法获取第一个匹配元素的html内容(innerHTML)。此属性在XML文档上不可用。 html( ) - 语法 selector.html( ) html( ) - 示例 以下是一个简单的示例,简单说明了此方法的用法- <html><head><title>The jQuery Example</title>…...
Linux vsftp三种模式的简单配置部署
环境:Debian 6.1.27-1kali1 (2023-05-12) vsftpd 安装 --查看是否当前系统是否已安装 apt list --installed | grep vsftpd 没有安装的话,就正常安装 apt-get update apt-get install vsftpd 一、匿名用户模式 分享一些不重要文件,任…...
6.1.tensorRT高级(1)-概述
目录 前言1. tensorRT高级概述总结 前言 杜老师推出的 tensorRT从零起步高性能部署 课程,之前有看过一遍,但是没有做笔记,很多东西也忘了。这次重新撸一遍,顺便记记笔记。 本次课程学习 tensorRT 高级-概述 课程大纲可看下面的思维…...
【Python】将M4A\AAC录音文件转换为MP3文件
文章目录 m4aaac 基础环境: sudo apt-get install ffmpegm4a 要将M4A文件转换为MP3文件,你可以使用Python中的第三方库pydub。pydub使得音频处理变得非常简单。在开始之前,请确保你已经安装了pydub库,如果没有,可以通…...
简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...
Admin.Net中的消息通信SignalR解释
定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...
《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...
新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案
随着新能源汽车的快速普及,充电桩作为核心配套设施,其安全性与可靠性备受关注。然而,在高温、高负荷运行环境下,充电桩的散热问题与消防安全隐患日益凸显,成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...
优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...
GruntJS-前端自动化任务运行器从入门到实战
Grunt 完全指南:从入门到实战 一、Grunt 是什么? Grunt是一个基于 Node.js 的前端自动化任务运行器,主要用于自动化执行项目开发中重复性高的任务,例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...
