封装一个vue3 多行文本超出省略展开/收起和tooltip展示组件

封装一个vue3 多行文本超出省略展开/收起和tooltip展示组件

前言

相信大家都能遇到这样一个问题,文本超出省略了,那么怎么既能让页面不被密密麻麻的文字占满,又能让所有的内容让用户能够清晰便捷地看到。在使用UI框架时我们常用tooltip组件去包裹过长的文本内容,但是,在我使用过程中存在这样一个问题,包裹的内容如果过短也展示了toltip,这样明显并不是最好地解决方案。以及在H5中使用tooltip也不是最好地选择,通常使用展开和收起来隐藏过长的文档。我将这两者结合起来,手动造轮子,手动封装一个通用组件。git地址:https://gitee.com/fcli/vue-text-overflow.git

先上图:

具体实现

展开和收起

1、首先需要实现展开和收起功能,使用css伪类增加展开和收起文字,通过浮动使文字能够环绕操作按钮,动态改变-webkit-line-clamp--bottom的值来调整段落样式,具体代码实现如下:

<input type="checkbox" class="exp" id="exp" v-show="false">
<div class="text" ref="textContent" :style="{ '--bottom': bottom, '-webkit-line-clamp': lineNum }">
    <label class="btn" ref="optBtn" for="exp" v-show="showExport && showExpBtn"></label>
    <slot></slot>
</div>

css样式,在展开和收起时动态改变文字容器的max-height来展示和隐藏内容。

.text {
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
    transition: .3s max-height;
}


.exp:checked+.text {
    max-height: 2000px;
    /*超出最大行高度就可以了*/
}

.exp:checked+.text {
    -webkit-line-clamp: 999 !important;
    /*设置一个足够大的行数就可以了*/
    max-height: none;
}

.exp:checked+.text .btn::after {
    content: '收起'
}

.exp:checked+.text .btn::before {
    visibility: hidden;
    /*在展开状态下隐藏省略号*/
}

.btn::after {
    content: '展开'
}


.text::before {
    content: '';
    float: right;
    width: 0;
    height: 100%;
    margin-bottom: var(--bottom);
}

.btn {
    margin-right: 12px;
    float: right;
    clear: both;
    cursor: pointer;
    color: #377ef9;
}

2、适配slot中的响应式,动态计算内容高度。使用MutationObserver监听节点的内容变化,当内容变化时通过判断scrollHeight是否大于clientHeight来展示展开操作。

onMounted(() => {
    getBtnHeight();
    const mutation = new MutationObserver(handleShowExp);
    const config = {
        attributes: true,
        characterData: true,
        childList: true,
        subtree: true,
        attributeOldValue: true,
        characterDataOldValue: true
    }
    mutation.observe(textContent.value, config);
})
//处理计算是否展示展开和收起按钮
const handleShowExp = () => {
    if (textContent.value.scrollHeight > textContent.value.clientHeight) {
        showExpBtn.value = true;
        getBtnHeight();
    }
}

const getBtnHeight = () => {
    //计算展开/收起按钮的高度,动态改变
    const offsetHeight = optBtn.value.offsetHeight - 2
    bottom.value = `-${offsetHeight}px`
    handelTooltip();
}
tooltip提示

经过查看elementui的popover和tooltip都是基于popperjs来二次封装的,因此我直接采用popperjs来实现tooltip功能。

1、首先通过npm安装popperjs。

npm i @popperjs/core

2、在页面中引用,并绑定对应dom,具体使用方法可参考官网:https://popper.js.org/

import { createPopper } from '@popperjs/core';

3、添加模板自定义tooltip内容

<div ref="tooltipRef" id="tooltip" v-if="showOverflowTooltip" class="tooltip" v-show="tooltipShow">
    <slot></slot>
    <div id="arrow" data-popper-arrow></div>
</div>

4、通过createPopper创建popover 并绑定触发事件,当鼠标mouseenter时展示tooltip,mouseleave时因此tooltip。

//处理tooltip事件
const handelTooltip = () => {

    const button: any = textContent.value;
    const tooltip: any = tooltipRef.value;

    const popperInstance = createPopper(button, tooltip, {
        placement: 'top',
        modifiers: [
            {
                name: 'offset',
                options: {
                    offset: [0, 8],
                },
            },
        ],
    });

    function show() {
        // Make the tooltip visible
        tooltipShow.value = true;

        // Enable the event listeners
        popperInstance.setOptions((options) => ({
            ...options,
            modifiers: [
                ...options.modifiers,
                { name: 'eventListeners', enabled: true },
            ],
        }));

        // Update its position
        popperInstance.update();
    }

    function hide() {
        tooltipShow.value = false;

        // Disable the event listeners
        popperInstance.setOptions((options) => ({
            ...options,
            modifiers: [
                ...options.modifiers,
                { name: 'eventListeners', enabled: false },
            ],
        }));
    }

    const showEvents = ['mouseenter', 'focus'];
    const hideEvents = ['mouseleave', 'blur'];

    showEvents.forEach((event) => {
        button.addEventListener(event, show);
    });

    hideEvents.forEach((event) => {
        button.addEventListener(event, hide);
    });
}

5、自定义tooltip样式

#arrow,
#arrow::before {
    position: absolute;
    width: 8px;
    height: 8px;
    background: inherit;
}

#arrow {
    visibility: hidden;
}

#arrow::before {
    visibility: visible;
    content: '';
    transform: rotate(45deg);
}

#tooltip[data-popper-placement^='top']>#arrow {
    bottom: -4px;
}

#tooltip[data-popper-placement^='bottom']>#arrow {
    top: -4px;
}

#tooltip[data-popper-placement^='left']>#arrow {
    right: -4px;
}

#tooltip[data-popper-placement^='right']>#arrow {
    left: -4px;
}

.tooltip {
    background: #333;
    color: #fff;
    border-radius: 4px;
    font-size: 14px;
    padding: 4px 8px;
    max-width: 300px;
}

使用

经过上面一系列搬砖,最终我们来试试效果吧。在app.vue中使用刚刚的组件:

<template>
  <div class="content">
    <vue-text-overflow :showOverflowTooltip="false" :showExport="true" :lineNum="3">
      这是一段文字<span style="color:red">带html标签</span>,文本超出省略溢出测试文本超出省略溢出测试文本超出省略溢出测试,文本超出省略溢出测试,文本超出省略溢出测试,文本超出省略溢出测试,文本超出省略溢出测试,文本超出省略溢出测试,文本超出省略溢出测试,文本超出省略溢出测试,文本超出省略溢出测试,文本超出省略溢出测试
    </vue-text-overflow>
    </div>
</template>

<script setup lang="ts">
import VueTextOverflow from './plugin/index.vue';
components:{
  VueTextOverflow
}
</script>

组件option如下所示:

属性属性名称类型可选值
showOverflowTooltip是否超出展示tooltipBooleanfalse
showExport是否展示展开/收起 操作按钮Booleantrue
lineNum超过多少行省略Number3

最后

本文只展示了部分主要源码,如果需要全部源码可访问git地址:https://gitee.com/fcli/vue-text-overflow.git
如果需要在项目中应用也可以通过npm直接安装:

npm install @fcli/vue-text-overflow --save-dev 来安装

在项目中使用
import vueTextOverflow from '@fcli/vue-text-overflow';
const app=createApp(App)
app.use(vueTextOverflow);

觉得不错,欢迎点赞收藏🙏

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Vue实现多行文本展开收起功能可以通过计算多行文本的高度来进行判断,并使用Vue的条件渲染来实现展开收起效果。 首先,在data中定义一个变量,例如`isExpanded`,用于控制文本展开收起状态,默认值设为`false`。 然后,在模板中使用条件渲染来根据`isExpanded`的值展示不同的内容。 例如,使用`v-if`指令来判断是否展开,如果展开则显示完整文本,否则只显示指定行数的文本。可以使用`v-text`指令来绑定文本内容。通过CSS的`line-clamp`属性来设置文本行数,超出的部分将被省略。 ``` <template> <div> <div v-if="isExpanded"> <div v-text="text"></div> </div> <div v-else> <div class="clamp-line" v-text="text"></div> </div> <button @click="toggleExpand"> {{ isExpanded ? '收起' : '展开' }} </button> </div> </template> <script> export default { data() { return { isExpanded: false, text: "这是一段多行文本" }; }, methods: { toggleExpand() { this.isExpanded = !this.isExpanded; } } }; </script> <style scoped> .clamp-line { display: -webkit-box; overflow: hidden; text-overflow: ellipsis; -webkit-line-clamp: 3; /* 设置为需要显示的行数 */ -webkit-box-orient: vertical; } </style> ``` 以上代码中,点击按钮时会触发`toggleExpand`方法,通过修改`isExpanded`的值来切换展开收起状态。根据`isExpanded`的值,使用不同的模板来渲染文本内容。 按钮的文本内容也根据`isExpanded`的值来显示“展开”或“收起”。点击按钮时,会调用`toggleExpand`方法切换`isExpanded`的值。 通过以上代码和样式设置,就可以实现一个简单的多行文本展开收起的功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叶落风尘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值