一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第15天,点击查看活动详情。
背景
相信很多小伙伴都遇到过这种需求,某某文字最多显示n行,超出n行显示...,并在文字最后显示展开收起按钮,举个例子:
上边的例子,是通过字符串截取的方法实现的,这种方法就导致展开按钮没办法靠到下方最右侧,不是特别的完美,nic今天给大家提供一个组件,实现咱们想要的效果。
直接上代码
// textOverflow.vue
<template>
<div ref="textOverflow" class="text-overflow" :style="boxStyle">
<span class="real-text" ref="overEllipsis">{{ realText }}</span>
<span class="slot-box" ref="slotRef" v-if="showSlotNode">
<slot :click-toggle="toggle" :expanded="expanded"></slot>
</span>
</div>
</template>
<script>
export default {
name: 'textOverflow',
props: {
// 具体的文本
text: {
type: String,
default: "",
},
// 收起时最多显示行数
maxLines: {
type: Number,
default: 3,
},
// 文字最外层宽度
width: {
type: Number,
default: 0,
},
},
data() {
return {
// 文字的显示长度
offset: this.text.length,
// 展开&收起
expanded: false,
// 展开&收起文字所占宽度
slotBoxWidth: 0,
// 文字最外层所占宽度
textBoxWidth: this.width,
// 是否展示收起展开按钮
showSlotNode: false,
};
},
computed: {
boxStyle() {
if (this.width) {
return {
width: this.width + "px",
};
}
},
realText() {
let that = this;
// 是否被截取
let isCutOut = that.offset !== that.text.length;
let realText = that.text;
if (isCutOut && !that.expanded) {
realText = that.text.slice(0, that.offset) + " ...";
}
return realText;
},
},
mounted() {
let that = this;
const { len } = that.getLines();
if (len > that.maxLines) {
that.showSlotNode = true;
that.$nextTick(() => {
that.slotBoxWidth = that.$refs.slotRef.clientWidth;
that.textBoxWidth = that.$refs.textOverflow.clientWidth;
that.calculateOffset(0, that.text.length);
});
}
},
methods: {
// 二分法获取最多显示文案数
calculateOffset(from, to) {
let that = this;
that.$nextTick(() => {
if (Math.abs(from - to) <= 1) return;
if (that.isOverflow()) {
to = that.offset;
} else {
from = that.offset;
}
that.offset = Math.floor((from + to) / 2);
that.calculateOffset(from, to);
});
},
// 判断是否显示正常
isOverflow() {
let that = this;
const { len, lastWidth } = that.getLines();
if (len < that.maxLines) {
return false;
}
if (that.maxLines) {
// 超出部分 行数 > 最大行数 或则 已经是最大行数但最后一行宽度 + 后面内容超出正常宽度
const lastLineOver = !!(len === that.maxLines && lastWidth + that.slotBoxWidth > that.textBoxWidth);
if (len > that.maxLines || lastLineOver) {
return true;
}
}
return false;
},
// 获取文字显示的行数和宽度
getLines() {
let that = this;
const clientRects = that.$refs.overEllipsis.getClientRects();
return {
len: clientRects.length,
lastWidth: clientRects[clientRects.length - 1].width,
};
},
// 展开收起
toggle() {
let that = this;
that.expanded = !that.expanded;
},
},
};
</script>
<style scoped lang="scss">
.slot-box {
display: inline-block;
float: right;
}
.text-overflow {
.real-text {
font-size: 14px;
color: #333333;
}
}
</style>
使用方法如下:
// 引入
import textOverflow from './textOverFlow.vue';
// 使用
<div style="width:200px">
<text-overflow :text="text" :maxLines="3">
<template v-slot:default="{ clickToggle, expanded }">
<button @click="clickToggle" class="btn">
{{ expanded ? "收起" : "展开" }}
</button>
</template>
</text-overflow>
</div>
效果如下:
大家可以在此基础上进行扩展哟!
感谢
谢谢你读完本篇文章,希望对你能有所帮助,如有问题欢迎各位指正。
我是Nicnic,如果觉得写得可以的话,请点个赞吧❤。
写作不易,「点赞」+「在看」+「转发」 谢谢支持❤