在 Vue 3 中实现“折叠”与“展开”文本内容

偶然间遇到一个场景,怎么判断一段文本是否超过 5 行或者指定行数,并在超过时显示 "展开/收起" 按钮。那应该如何实现呢?

在 Vue 3 的项目下实现:

html 复制代码
<template>
  <div class="text-container">
    <div class="text-content" ref="textContentRef" :class="{ collapsed: showFullText }">
      {{ longText }}
    </div>
    <!-- 仅在内容超过 5 行时显示展开/收起按钮 -->
    <button v-if="isOverflowing" @click="toggleText" class="toggle-btn">
      {{ showFullText ? '收起' : '展开' }}
    </button>
  </div>
</template>

<script setup>
import { ref, onMounted, nextTick } from 'vue'

// showFullText:记录当前文本是展开还是折叠状态
const showFullText = ref(false)
// isOverflowing:用来判断文本是否超出了 5 行
const isOverflowing = ref(false)
const textContentRef = ref(null)

// 模拟长文本
const longText = `
  这是一个很长的文本,可以用来展示折叠效果。这个文本很长很长,需要在界面上显示多行,而我们希望默认显示 5 行的内容。
  如果超过 5 行,则展示展开按钮。点击展开按钮后,显示所有内容。如果再次点击收起按钮,恢复到 5 行展示。
  心灵鸡汤(凑字数):所有的失败都是为成功做准备。抱怨和泄气,只能阻碍成功向自己走来的步伐。
  放下抱怨,心平气和地接受失败,无疑是智者的姿态。抱怨无法改变现状,拼搏才能带来希望。
  真是金子,只要自己不把自己埋没,只要一心想着闪光,就总有闪光的那一天。
`

// 切换展开和收起状态
const toggleText = () => {
  showFullText.value = !showFullText.value
}

// 计算是否溢出 5 行
const calculateOverflow = () => {
  const el = textContentRef.value
  if (el) {
    const lineHeight = parseFloat(getComputedStyle(el).lineHeight) // 获取行高
    const maxVisibleHeight = lineHeight * 5 // 计算出 5 行的最大高度
    // scrollHeight:内容的实际高度(包含不可见部分)
    isOverflowing.value = el.scrollHeight > maxVisibleHeight // 判断是否超出 5 行
  }
}

// 在组件挂载时执行文本溢出检查
onMounted(() => {
  nextTick(() => {
    calculateOverflow()
  })
})
</script>

<style scoped>
.text-container {
  max-width: 600px;
  margin: 0 auto;
  font-size: 16px;
  line-height: 1.5;
  border: 2px solid pink;
  border-radius: 5px;
  padding: 18px;
}

.text-content {
  overflow: hidden;
  display: -webkit-box; /* 需要这行以启用多行省略号 */
  -webkit-box-orient: vertical; /* 垂直排列 */
  -webkit-line-clamp: 5; /* 限制为 5 行 */
  max-height: calc(5 * 1.5em); /* 5 行的最大高度 */
  transition: max-height 0.3s ease; /* 添加过渡效果 */
}

.text-content.collapsed {
  max-height: none; /* 展开时显示所有内容 */
  -webkit-line-clamp: unset; /* 移除行数限制 */
}

.toggle-btn {
  background-color: transparent;
  border: none;
  color: orange;
  cursor: pointer;
  margin-top: 10px;
  padding: 0;
}
</style>

展示为:

对代码进行注释:

1、text-content 是存放长文本的地方,默认显示 5 行,超出部分通过 max-height 和 -webkit-line-clamp 进行隐藏,并通过 transition 实现展开/折叠的动画效果。

2、collapsed 类控制文本展开时移除 max-height 和 -webkit-line-clamp,显示所有内容。

注意📢:

1、line-height 与行数计算

这里的 line-height 被设定为 1.5,表示每行的高度是文本字体大小的 1.5 倍。在实际项目中,需要根据实际的 line-height 和字体大小来调整。

2、-webkit-line-clamp 属性

-webkit-line-clamp 是一个非标准的 CSS 属性,兼容性需要注意,尤其是在非 WebKit 内核的浏览器中。

3、性能考虑

计算 scrollHeight 和 clientHeight 的操作会触发浏览器的重排(Reflow),因此建议避免在高频操作中使用,如 resize 或 scroll 事件中。

其他实现方法

1、使用 JavaScript 动态裁剪文本字符串,只显示前 n 个字符,剩余部分用省略号 ... 替代。

javascript 复制代码
const shortenedText = longText.slice(0, 100) + '...';

但可能没有办法指定行数

2、使用第三方库,比如:Clamp.js,它可以更灵活地处理多行文本的裁剪和展开。

javascript 复制代码
Clamp(document.getElementById('my-text'), { clamp: 5 });

总结:

上述例子展示了如何在 Vue 3 中动态判断文本是否超出 5 行,并通过按钮实现折叠和展开功能。

相关推荐
修炼室18 分钟前
从拥堵到畅通:HTTP/2 如何解决 Web 性能瓶颈?
前端·网络协议·http
让开,我要吃人了43 分钟前
HarmonyOS鸿蒙开发实战( Beta5.0)页面加载效果实现详解实践案例
开发语言·前端·华为·移动开发·harmonyos·鸿蒙·鸿蒙系统
洞窝技术2 小时前
重塑前端开发:如何利用 micro-app 实现高效微前端架构
前端·javascript
吕彬-前端2 小时前
使用vite+react+ts+Ant Design开发后台管理项目(三)
前端·javascript·react.js
想做一只快乐的修狗2 小时前
【react案例】实现评论列表
前端·react.js·前端框架
m0_719414562 小时前
【Vue.js基础】
前端·vue.js·flutter
fxshy2 小时前
01-Cesium添加泛光线
开发语言·前端·javascript
Hanking652032 小时前
Android程序员怎么从零到一开发一个自己的AI小程序并上线
前端·微信小程序·小程序·云开发
丹丹的笑意2 小时前
学习记录:js算法(四十七):相同的树
javascript·学习·算法
聊天宝快捷回复2 小时前
必收藏,售后客服日常回复必备的话术 (精华版)
java·前端·数据库·经验分享·微信·职场发展·快捷回复