多行文字超出部门截断,并且可以展开收起。这个需求其实很容易实现,只需要 CSS 和一点简单的 JS 就可以。本文只讨论利用 css 截断,不考虑直接截取文字(不付费不给看剩余内容)的情况。
实现一个基础版本 1.0
<div class="more-text">文字内容。。。</div>
在此使用了 css 变量,row 是可以配置的,height 根据 row 计算。 需要先在 js 中给 css 变量赋值,然后在 style 中使用
refMoreText.value.style.setProperty('--row', props.row)
refMoreText.value.style.setProperty('--height', textHeight + 'px')
.more-text {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
word-break: break-all;
white-space: pre-wrap;
-webkit-line-clamp: var(--row);
line-clamp: var(--row);
height: var(--height);
省略号效果实现了,然后加一个 展开/收起效果,修改html 如下:
增加几个 ref
便于计算高度,isExceed
表示是否超出高度,如果为 true,显示“展开更多”,反之不显示。
<div ref="refMoreText" class="more-text">
<div ref="refContent" class="content">{{ text }}</div>
<div
ref="refTrigger"
class="trigger text-primary trigger-bg"
@click="handleTrigger"
v-if="isExceed"
>
<span>{{ moreVisible ? '收起' : '... 展开更多' }}</span>
</div>
</div>
...
// 实际内容的高度
fullHeight = refContent.value.clientHeight
// 文本的行高,用于计算 n 行所占的高度
lineHeight = Number(window.getComputedStyle(refMoreText.value).lineHeight.slice(0, -2))
// n 行的高度
textHeight = lineHeight * props.row
// 判断是否超出高度
isExceed.value = textHeight < fullHeight
...
这里 css 有一个小技巧,我们把content的 position 设为 absolute,这样它不会被父元素的高度影响,始终可以获取自身实际高度。
.content {
// 设为absolute,避免高度被父元素影响
position: absolute;
height: auto;
}
在此获取实际文本的高度,还有一个重要作用:当我们使用 transition 来实现展开折叠的动画效果,需要有开始高度和结束高度,我们知道如果把结束高度 height设为 auto,那么这个动画就出不来,展开效果比较生硬。
另一个 css 小技巧:我们给“展开更多”加了一点背景,让它和文字看起来更协调
.trigger-bg {
background: linear-gradient(
to right,
rgb(255, 255, 255, 0) 0,
rgb(255, 255, 255, 1) 60%,
#fff 100%
);
}
接下来,我们通过文本展开/折叠状态,设置对应的 css 变量
// visible
// true:展开,false:折叠
const setCssVar = (visible: boolean) => {
if (visible) {
refMoreText.value.style.setProperty('--height', fullHeight + lineHeight + 'px')
refMoreText.value.style.setProperty('--row', '')
} else {
refMoreText.value.style.setProperty('--row', props.row)
// 收起在文本下面,所以额外增加一行的高度
refMoreText.value.style.setProperty('--height', textHeight + 'px')
}
}
至此,已经实现了 1.0 版本,但是有一点小问题:在改变窗口大小或者容器大小时,展开内容的高度不会变,收起按钮的位置也不会跟着变化。
我希望它具有更好的自适应能力。接着写 1.1 版本
增强自适应能力
通过监听内容区域的变化,实时改变元素的高度。这里使用 Resize Observer API
(文档参考:developer.mozilla.org/zh-CN/docs/… resize 事件`,Resize Observer的性能更优。
let resizeObserver: ResizeObserver | null = null
onMounted(async () => {
fullHeight = refContent.value.clientHeight
lineHeight = Number(window.getComputedStyle(refMoreText.value).lineHeight.slice(0, -2))
textHeight = lineHeight * props.row
if (refTrigger.value) refTrigger.value.style['lineHeight'] = lineHeight + 'px'
resizeObserver = new ResizeObserver((entries) => {
for (let entry of entries) {
fullHeight = entry.contentRect.height
isExceed.value = textHeight < fullHeight
setCssVar(moreVisible.value)
}
})
resizeObserver.observe(refContent.value)
})
const unobserveElementSize = () => {
if (resizeObserver) {
resizeObserver.disconnect()
resizeObserver = null
}
}
onUnmounted(() => {
unobserveElementSize()
})
OK,至此已经实现了我需要的功能
项目地址
本项目GIT地址:github.com/lucidity99/…
如果有帮助,给个star ✨ 点个赞