diy了两种文本超出处理组件,组件一是在原位置呈现全部文本,组件二是弹窗显示全部文本,直接复制可食用,废话不多说,直接上菜
效果图
缩略效果图
组件一展开效果
组件二展开效果
组件一
TextOverflow
<template>
<!-- 内容容器 -->
<div class="content-box" ref="containerRef">
<!-- 文本内容区域,根据是否展开切换样式 -->
<div
ref="contentRef"
class="content-text"
:class=" isExpanded ? 'text-expanded': 'text-ellipsis'"
@click="handleTextClick"
>
{{ content }}
</div>
<div
v-if="showMoreBtn"
class="show-more"
@click.stop="toggleExpand"
>
{{ isExpanded ? '收起' : '查看更多' }}
</div>
</div>
</template>
<script>
export default {
props: {
// 文本内容
content: {
type: String,
default: ''
},
// 最大显示行数
maxLines: {
type: Number,
default: 3
}
},
data() {
return {
isExpanded: false, // 是否展开全部内容
showMoreBtn: false // 是否需要显示"查看更多"按钮
}
},
mounted() {
// 初始化时检查文本是否溢出
this.checkTextOverflow()
// 添加窗口resize事件监听
window.addEventListener('resize', this.handleResize)
},
beforeDestroy() {
// 组件销毁前移除事件监听
window.removeEventListener('resize', this.handleResize)
},
methods: {
/**
* 检查文本是否超出指定行数
*/
checkTextOverflow() {
this.$nextTick(() => {
const contentEl = this.$refs.contentRef
if (!contentEl) return
// 获取行高和内容高度
const lineHeight = parseInt(window.getComputedStyle(contentEl).lineHeight)
const scrollHeight = contentEl.scrollHeight // 内容总高度
const clientHeight = contentEl.clientHeight // 可视高度
// 判断是否需要显示"查看更多"按钮
this.showMoreBtn = scrollHeight > clientHeight ||
(scrollHeight > (lineHeight * this.maxLines))
})
},
/**
* 切换展开/收起状态
*/
toggleExpand() {
this.isExpanded = !this.isExpanded
},
/**
* 处理文本点击事件
*/
handleTextClick() {
// 如果内容超出,点击文本也可以切换展开状态
if (this.showMoreBtn) {
this.toggleExpand()
}
},
/**
* 防抖处理的resize事件处理函数
*/
handleResize: debounce(function() {
// 如果已经展开,不需要处理
if (this.isExpanded) return
// 重新检查文本溢出情况
this.checkTextOverflow()
}, 100)
},
// 监听content变化
watch: {
content() {
this.isExpanded = false
this.checkTextOverflow()
}
}
}
/**
* 防抖函数
* @param {Function} fn 要执行的函数
* @param {Number} delay 延迟时间(ms)
*/
function debounce(fn, delay) {
let timer = null
return function() {
clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, arguments)
}, delay)
}
}
</script>
<style scoped>
/* 内容容器样式 */
.content-box {
position: relative;
padding-bottom: 24px; /* 为"查看更多"按钮预留空间 */
}
/* 文本基础样式 */
.content-text {
line-height: 1.5; /* 行高 */
word-break: break-word; /* 长单词换行 */
cursor: pointer; /* 鼠标手型 */
}
/* 省略号样式 - 当文本未展开时 */
.text-ellipsis {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3; /* 限制显示行数 */
line-clamp: 3;
overflow: hidden;
text-overflow: ellipsis; /* 文本溢出显示省略号 */
}
/* 展开样式 - 当文本展开时 */
.text-expanded {
display: block; /* 恢复默认显示 */
}
/* 查看更多/收起按钮样式 */
.show-more {
position: absolute;
right: 0;
bottom: 0;
color: #409EFF; /* 主题蓝色 */
cursor: pointer;
padding-left: 8px; /* 左侧内边距 */
font-size: 14px;
}
/* 按钮悬停效果 */
.show-more:hover {
text-decoration: underline; /* 添加下划线 */
}
</style>
组件二
TextOverflowShowDialog
<template>
<!-- 内容容器 -->
<div class="content-box" ref="containerRef">
<!-- 文本内容区域 -->
<div
ref="contentRef"
class="content-text"
:class="showMoreBtn ? 'text-ellipsis' : 'text-expanded'"
@click="handleTextClick"
>
{{ content }}
</div>
<!-- 显示更多按钮 -->
<div
v-if="showMoreBtn"
class="show-more"
@click.stop="openDialog"
>
查看更多
</div>
</div>
<!-- 内容详情弹窗 -->
<el-dialog
v-model="showDialog"
class="custom-content-dialog"
:title="dialogTitle"
@close="showDialog = false"
append-to-body
width="900px"
>
<el-scrollbar class="custom-dialog-scrollbar" height="60vh">
<div class="custom-dialog-content">
{{ content }}
</div>
</el-scrollbar>
<template #footer>
<el-button @click="showDialog = false">关闭</el-button>
</template>
</el-dialog>
</template>
<script>
export default {
props: {
// 文本内容
content: {
type: String,
default: ''
},
// 最大显示行数,默认为3行
maxLines: {
type: Number,
default: 3
},
// 弹窗标题
dialogTitle: {
type: String,
default: '内容详情'
}
},
data() {
return {
showDialog: false, // 是否显示弹窗
showMoreBtn: false // 是否需要显示"查看更多"按钮
}
},
mounted() {
this.checkTextOverflow()
window.addEventListener('resize', this.handleResize)
},
beforeDestroy() {
window.removeEventListener('resize', this.handleResize)
},
methods: {
/**
* 检查文本是否超出指定行数
*/
checkTextOverflow() {
this.$nextTick(() => {
const contentEl = this.$refs.contentRef
if (!contentEl) return
const lineHeight = parseInt(window.getComputedStyle(contentEl).lineHeight)
const scrollHeight = contentEl.scrollHeight
const clientHeight = contentEl.clientHeight
this.showMoreBtn = scrollHeight > clientHeight ||
(scrollHeight > (lineHeight * this.maxLines))
})
},
/**
* 打开详情弹窗
*/
openDialog() {
this.showDialog = true
},
/**
* 处理文本点击事件
*/
handleTextClick() {
if (this.showMoreBtn) {
this.openDialog()
}
},
/**
* 防抖处理的resize事件处理函数
*/
handleResize: debounce(function() {
this.checkTextOverflow()
}, 100)
},
watch: {
content() {
this.showDialog = false
this.checkTextOverflow()
}
}
}
/**
* 防抖函数
*/
function debounce(fn, delay) {
let timer = null
return function() {
clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, arguments)
}, delay)
}
}
</script>
<style scoped>
/* 内容容器样式 */
.content-box {
position: relative;
padding-bottom: 24px;
}
/* 文本基础样式 */
.content-text {
line-height: 1.5;
word-break: break-word;
cursor: pointer;
}
/* 省略号样式 */
.text-ellipsis {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
line-clamp: 3;
overflow: hidden;
text-overflow: ellipsis;
}
/* 展开样式 */
.text-expanded {
display: block;
}
/* 查看更多按钮样式 */
.show-more {
position: absolute;
right: 0;
bottom: 0;
color: #409EFF;
cursor: pointer;
padding-left: 8px;
font-size: 14px;
}
.show-more:hover {
text-decoration: underline;
}
</style>
<style>
.custom-content-dialog {
max-height: 80vh;
}
.custom-content-dialog .el-dialog__body {
padding: 15px 20px;
}
.custom-dialog-scrollbar {
max-height: 60vh;
}
.custom-dialog-content {
white-space: pre-wrap;
word-break: break-word;
line-height: 1.6;
padding-right: 10px;
}
</style>
使用
需要的地方直接引入使用即可
<!-- <text-overflow :content="row.excMessage"></text-overflow>-->
<text-overflow-show-dialog :content="row.excMessage"></text-overflow-show-dialog>