在 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 行,并通过按钮实现折叠和展开功能。

相关推荐
passerby606113 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了13 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅13 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅14 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅14 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment14 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅14 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊14 小时前
jwt介绍
前端
爱敲代码的小鱼14 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax
吹牛不交税15 小时前
admin.net-v2 框架使用笔记-netcore8.0/10.0版
vue.js·.netcore