You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue评论区多行内容时显示Read More/Hide按钮的实现问题

解决Vue评论区仅多行内容显示Read More/Hide按钮的问题

问题核心

开发类YouTube评论区组件时,需要实现仅当评论内容超过2行时才显示Read More/Hide按钮,目前已通过-webkit-line-clamp实现折叠/展开,但按钮会在所有评论中显示;尝试用content.height()判断无效(因为content是字符串,无DOM元素的height方法)。

可行解决方案

核心思路是通过DOM元素的实际高度对比判断内容是否超出:当元素的scrollHeight(内容总高度)大于clientHeight(容器显示高度)时,说明内容被折叠,需要显示按钮。

代码修改步骤

  1. 给评论内容的<p>标签添加ref,用于获取DOM元素
  2. 添加数据属性shouldShowButton控制按钮显示
  3. 在组件挂载/内容更新时,通过$nextTick确保DOM渲染完成后,判断高度并更新shouldShowButton
  4. 调整按钮容器的显示逻辑,仅在shouldShowButton为true时渲染

修改后的完整代码

<template>
    <div>
        <div class="d-flex flex-row align-items-center">
            <h4 class="card-title">{{ author }}</h4>
            <h6 class="card-subtitle text-muted ml-3">
                {{ timeAgo(createdAt) }} ago
            </h6>
        </div>
        <!-- 添加ref用于获取DOM元素 -->
        <p ref="commentContent" class="multiline" :style="{ '-webkit-line-clamp': lineclamp }">
            <b class="timestamp" v-if="timestamp !== null">@{{ timeToHHMMSS(timestamp) }}</b> 
            {{ content }}
        </p>
        <!-- 仅当shouldShowButton为true时显示按钮容器 -->
        <div v-if="shouldShowButton">
            <base-button v-show="!readmore" @click="changeLineclamp()" link class="text-white p-0" size="sm">Read more</base-button>
            <base-button v-show="readmore" @click="hideContent()" link class="text-white p-0" size="sm">Hide</base-button>
        </div>
    </div>
</template>
  
<script>
import { timeSince, toHHMMSS } from "@/plugins/timeControls.js";

export default {
    name: "comment-item",
    data() {
        return {
            lineclamp: 2,
            readmore: false,
            shouldShowButton: false, // 新增:控制按钮显示
        }
    },
    props: {
        id: { type: String, required: true },
        author: { type: String, required: true },
        createdAt: { type: Number, required: true },
        timestamp: { type: Number, required: true },
        content: { type: String, required: true },
    },
    methods: {
        changeLineclamp() {
            this.lineclamp = 'initial';
            this.readmore = true;
        },
        hideContent() {
            this.lineclamp = 2;
            this.readmore = false;
            // 隐藏后重新判断是否需要显示按钮
            this.checkContentHeight();
        },
        timeAgo(date) {
            return timeSince(date);
        },
        timeToHHMMSS(time) {
            return toHHMMSS(time);
        },
        // 封装高度判断逻辑
        checkContentHeight() {
            this.$nextTick(() => {
                const contentEl = this.$refs.commentContent;
                if (!contentEl) return;
                // scrollHeight > clientHeight 说明内容超出容器高度
                this.shouldShowButton = contentEl.scrollHeight > contentEl.clientHeight;
            });
        },
    },
    // 挂载时判断
    mounted() {
        this.checkContentHeight();
    },
    // 内容更新时重新判断(适配父组件传值变化)
    updated() {
        this.checkContentHeight();
    },
};
</script>
  
<style lang="scss" scoped>
@import "@/assets/sass/dashboard/custom/_variables.scss";

ul {
    list-style-type: none;
    padding: 0;
}

.timestamp {
    color: $primary;
}

.multiline {
    overflow: hidden;
    text-overflow: ellipsis;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    /* 固定行高,确保高度判断准确 */
    line-height: 1.5;
    max-height: calc(2 * 1.5em); /* 2行的高度,和line-clamp对应 */
}
</style>

关键优化点

  • 移除无用的computedLineclamp计算属性,直接使用lineclamp数据属性
  • 给.multiline添加max-height和固定line-height,确保高度判断的准确性
  • 封装checkContentHeight方法,复用高度判断逻辑
  • 在updated钩子中重新判断,适配内容动态变化的场景

为什么原来的content.height()无效?

content是父组件传入的字符串类型的评论内容,并非DOM元素,因此没有height()方法(该方法是jQuery对DOM元素的封装),必须通过ref获取实际渲染的DOM元素后,才能读取其高度属性。

内容的提问来源于stack exchange,提问作者dounia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 08:45:38