1.使用双边逼近法截取字符串长度
<template>
<div>
<div ref="textContainerRef" class="text-container" v-if="!isExpanded">
<div>
{{ displayedText }}
<span v-if="showMoreButton">...</span>
<span v-if="showMoreButton" @click="expandText">显示更多</span>
</div>
</div>
<div v-if="isExpanded">
{{ fullText }}
</div>
</div>
</template>
<script setup>
import { ref, onMounted, nextTick, watch } from "vue";
const textContainerRef = ref(null);
const fullText =
"这是一个很长的文本,它将被截断以适应两行的显示。如果文本太长,那么我们需要找到一个合适的位置来截断它。这是测试文本,看看是否真的能截断。这是一个很长的文本,它将被截断以适应两行的显示。如果文本太长,那么我们需要找到一个合适的位置来截断它。这是测试文本,看看是否真的能截断。这是一个很长的文本,它将被截断以适应两行的显示。如果文本太长,那么我们需要找到一个合适的位置来截断它。这是测试文本,看看是否真的能截断。这是一个很长的文本,它将被截断以适应两行的显示。如果文本太长,那么我们需要找到一个合适的位置来截断它。这是测试文本,看看是否真的能截断。这是一个很长的文本,它将被截断以适应两行的显示。如果文本太长,那么我们需要找到一个合适的位置来截断它。这是测试文本,看看是否真的能截断。这是一个很长的文本,它将被截断以适应两行的显示。如果文本太长,那么我们需要找到一个合适的位置来截断它。这是测试文本,看看是否真的能截断。";
const isExpanded = ref(false);
const displayedText = ref("");
const showMoreButton = ref(false);
const expandText = () => {
isExpanded.value = true;
};
const recursiveBinarySearch = async (text, start, end) => {
if (start >= end) {
displayedText.value = text.substring(0, end);
showMoreButton.value = displayedText.value.length < fullText.length;
return end;
}
const mid = Math.floor((start + end) / 2);
displayedText.value = text.substring(0, mid) + "...查看更多";
// console.log(displayedText.value)
await nextTick(() => {
if (
textContainerRef.value.scrollHeight <= textContainerRef.value.clientHeight
) {
// 继续向右搜索,寻找更长的文本
return recursiveBinarySearch(text, mid + 2, end);
} else {
// 否则,向左搜索,尝试减少文本长度
return recursiveBinarySearch(text, start, mid - 2);
}
});
};
onMounted(async () => {
await recursiveBinarySearch(fullText, 0, fullText.length);
});
</script>
<style scoped>
.text-container {
max-height: 40px;
line-height: 20px;
overflow: hidden;
position: relative;
}
button {
position: absolute;
bottom: 0;
right: 0;
}
</style>
效果如下
2.css浮动实现
有个问题before里的给了高度,会导致yuanqu-con最小高度就是before里的写死的高度
<template>
<div class="yuanqu-con">
<div class="text" ref="myDiv" v-if="iaAll === 0">
<span class="btn" v-if="isMore === 1" @click="handleMore">查看更多</span>
<div class="text-con" ref="textMore">
{{ fullText }}
</div>
</div>
<div v-if="iaAll === 1">
{{ fullText }}
</div>
</div>
</template>
<script setup>
import { ref, onMounted, nextTick, watch } from "vue";
import { is } from "./utils/is";
const fullText =
"这是一个很长的文本,它将被截断以适应两行的显示。如果文本太长,那么我们需要找到一个合适的位置来截断它。这是测试文本,看看是否真的能截断。这是一个很长的文本,它将被截断以适应两行的显示。如果文本太长,那么我们需要找到一个合适的位置来截断它。这是测试文本,看看是否真的能截断。这是一个很长的文本,它将被截断以适应两行的显示。如果文本太长,那么我们需要找到一个合适的位置来截断它。这是测试文本,看看是否真的能截断。这是一个很长的文本,它将被截断以适应两行的显示。如果文本太长,那么我们需要找到一个合适的位置来截断它。这是测试文本,看看是否真的能截断。这是一个很长的文本,它将被截断以适应两行的显示。如果文本太长,那么我们需要找到一个合适的位置来截断它。这是测试文本,看看是否真的能截断。这是一个很长的文本,它将被截断以适应两行的显示。如果文本太长,那么我们需要找到一个合适的位置来截断它。这是测试文本,看看是否真的能截断。这是一个很长的文本,它将被截断以适应两行的显示。如果文本太长,那么我们需要找到一个合适的位置来截断它。这是测试文本,看看是否真的能截断。这是一个很长的文本,它将被截断以适应两行的显示。如果文本太长,那么我们需要找到一个合适的位置来截断它。这是测试文本,看看是否真的能截断。这是一个很长的文本,它将被截断以适应两行的显示。如果文本太长,那么我们需要找到一个合适的位置来截断它。这是测试文本,看看是否真的能截断。这是一个很长的文本,它将被截断以适应两行的显示。如果文本太长,那么我们需要找到一个合适的位置来截断它。这是测试文本,看看是否真的能截断。这是一个很长的文本,它将被截断以适应两行的显示。如果文本太长,那么我们需要找到一个合适的位置来截断它。这是测试文本,看看是否真的能截断。这是一个很长的文本,它将被截断以适应两行的显示。如果文本太长,那么我们需要找到一个合适的位置来截断它。这是测试文本,看看是否真的能截断。";
const myDiv = ref(null);
const textMore = ref(null);
const isMore = ref(0);
const iaAll = ref(0);
nextTick(() => {
// 判断div的高度是否显示按钮
if (textMore.value.scrollHeight >= myDiv.value.clientHeight) {
isMore.value = 1;
} else {
isMore.value = 0;
}
});
function handleMore() {
iaAll.value = 1;
}
</script>
<style scoped>
.yuanqu-con {
width: 1139px;
font-size: 14px;
color: #202332;
}
.yuanqu-con .text {
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
.yuanqu-con .text::before {
content: "";
float: right;
height: 39px;
background: #fff;
}
/* 保留注释,因为它们在 CSS 中也是合法的 */
/* .yuanqu-con .text::after {
content: '';
width: 100%;
height: 65px;
position: absolute;
background: #fff;
} */
.yuanqu-con .btn {
float: right;
clear: both;
cursor: pointer;
color: #4876ff;
}
</style>
效果如下