前言

功能说明

Vue3版本实现、css部分使用TailWind

TODO: 有部分瑕疵,可继续优化。

1.支持控制行数

2.过渡动画使用

3.可改为插槽

实现

<template>
<div
:class="[
`text-[${fontSize}px]`,
'overflow-hidden',
'transition-height duration-500 ease-in-out',
(showSuspension && !expanded) ? 'suspension' : ''
]"
:style="{
lineHeight: `${fontSize * props.lineHeightScale}px `,
maxHeight: !expanded ? `${fontSize * maxLines * props.lineHeightScale}px` : `${height}px`,
}"
>
<div
v-resize="getHeight"
v-highlight="props.text"
></div>
</div>
<div class="flex items-center justify-center cursor-pointer" ref="slotRef" v-if="showSuspension">
<a class="mt-2" @click="toggle"> {{ expanded ? closeText : openText }} </a>
</div>
</template>

<script lang="ts" setup>
import { onMounted, ref } from 'vue';
import { vHighlight } from '/@/directives/text';

const props = withDefaults(
defineProps<{
text: string;
maxLines: number;
fontSize: number;
lineHeightScale: number;
openText: string;
closeText: string;
}>(),
{
text: '',
maxLines: 3,
fontSize: 14,
lineHeightScale: 1.5,
openText: '查看更多',
closeText: '收起',
},
);

let expanded = ref<boolean>(false);
let slotRef = ref<HTMLElement>();
const showSuspension = ref(false);
const height = ref<number>(0);
const getHeight = (rect: ClientRect) => {
height.value = rect.height;
console.log('height: ', rect.height);
if (rect.height > props.fontSize * props.maxLines * props.lineHeightScale) {
showSuspension.value = true;
} else {
showSuspension.value = false;
}
};

const toggle = () => {
expanded.value = !expanded.value;
};
onMounted(() => {});
</script>

<style scoped lang="less">
.suspension {
position: relative;
&::after {
background: linear-gradient(90deg, hsla(0, 0%, 100%, 0.5), #fff 40%);
bottom: 0;
content: '...';
padding-left: 30px;
position: absolute;
right: 0;
width: 50px;
z-index: 100;
}
}
</style>