Vue3封装“展开”与“折叠”文本内容组件

最近项目中遇到一个需求,文字太多时需要展开与折叠,一开始我使用了antdesign vue中的Typography 组件,但是我发现,这个组件展开之后没有办法折叠,搜索了很多都没找到方法,于是参考这篇文章成功自己封装了一个组件,另外增加了复制功能。

<template>
    <div v-show="props.content">
        <p :class="[expanded ? 'ellipsis' : '', 'text-content']" ref="textContentRef">
            {{ props.content }}
        </p>
        <a-button v-if="isOverflowing" size="small" type="link" @click="expanded = !expanded">{{ expanded ? '收起' : '展开'
        }}</a-button>
        <a-button type="link" size="small" @click="copy(props.content)">复制</a-button>
    </div>
</template>
<script setup>
import { ref, defineProps, nextTick, watch } from 'vue';
import { message } from 'ant-design-vue';
import { useClipboard } from '@vueuse/core'
const props = defineProps(['content'])
const expanded = ref(false)
// isOverflowing:用来判断文本是否超出了 5 行
const isOverflowing = ref(false)
const textContentRef = ref()
// 计算是否溢出 1 行
const calculateOverflow = () => {
    const el = textContentRef.value
    if (el) {
        const lineHeight = parseFloat(window.getComputedStyle(el).lineHeight) // 获取行高
        const maxVisibleHeight = lineHeight * 1 // 计算出 1 行的最大高度
        // scrollHeight:内容的实际高度(包含不可见部分)
        isOverflowing.value = el.scrollHeight > maxVisibleHeight // 判断是否超出 1 行
    }
}
const copy = (content) => {
    const { copy } = useClipboard({ legacy: true })
    copy(content)
    message.success('复制成功');
}
watch(() => props.content, () => {
    nextTick(() => {
        calculateOverflow()
    })
})
</script>
<style scoped>
p {
    color: #000;
    margin: 0;
    word-break: break-all;
    line-height: 1.5;
}

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

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

.ant-btn-link {
    padding-left: 0;
}
</style>

### Vue 中实现文本过长时的展开和收起功能 在 Vue 应用程序中,可以通过自定义组件来实现文本过长时自动折叠并提供“显示更多”按钮的功能。以下是具体实现方法: #### 使用 `vue-paragraph` 组件库 可以利用第三方库 `vue-paragraph` 来简化开发过程[^1]。 安装依赖: ```bash npm install vue-paragraph --save ``` 引入并在项目中注册该插件: ```javascript import Vue from &#39;vue&#39;; import Paragraph from &#39;vue-paragraph&#39;; Vue.use(Paragraph); ``` 模板部分可以直接调用 `<expandable>` 标签,默认情况下它会呈现为可扩展模式。 ```html <template> <div id="app"> <!-- 默认配置 --> <expandable :text="&#39;这是一段非常长的文字...&#39;" /> <!-- 自定义行数和其他属性 --> <expandable :text="&#39;另一段更长的内容...&#39;" :max-lines="3" more-text="显示全部" less-text="隐藏内容"/> </div> </template> ``` #### 手动编写逻辑代码 如果不希望依赖外部包,则可以在本地创建一个新的 Vue 单文件组件来自行管理状态变化][^[^23]。 HTML 结构如下所示: ```html <div class="content" ref="textContent">{{ visibleText }}</div> <button @click="toggleContent">{{ buttonText }}</button> ``` JavaScript 部分负责切换可见性和更新 UI 显示文字: ```javascript export default { data() { return { isExpanded: false, originalText: &#39;很长的一篇文章...&#39;, truncatedText: &#39;&#39;, maxLines: 3, // 控制最大显示几行 }; }, computed: { visibleText() { return this.isExpanded ? this.originalText : this.truncatedText; }, buttonText() { return this.isExpanded ? &#39;收起&#39; : &#39;显示更多&#39;; } }, mounted() { const el = this.$refs.textContent.cloneNode(true); let textCopy = document.createElement(&#39;span&#39;); textCopy.style.visibility = &#39;hidden&#39;;// 不影响布局计算高度 textCopy.innerHTML = this.originalText; document.body.appendChild(textCopy); const lineHeight = parseInt(window.getComputedStyle(el).lineHeight); const maxHeight = lineHeight * this.maxLines; if (el.offsetHeight > maxHeight) { this.truncatedText = `${this.originalText.slice( 0, Math.floor(maxHeight / lineHeight) * window.getComputedStyle(el).fontSize.replace(/px/, &#39;&#39;) )} ...`; } else { this.truncatedText = this.originalText; } document.body.removeChild(textCopy); }, methods: { toggleContent() { this.isExpanded = !this.isExpanded; } } }; ``` CSS 设置样式以确保溢出部分内容被裁剪掉,并添加省略号提示用户有更多信息未显示出来: ```css .content { display: -webkit-box; overflow: hidden; white-space: normal!important; word-break: break-all; text-overflow: ellipsis; -webkit-line-clamp: v-bind(&#39;maxLines&#39;); /* 行数 */ -webkit-box-orient: vertical; } ``` 通过上述两种方式之一即可轻松完成对较长文本片段按需展示的需求,在实际应用过程中可根据业务场景灵活调整参数设置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值