展示效果


组件
javascript
<template>
<view class="address-container">
<!-- 1. 实际显示的文本区域 -->
<!-- 如果未展开:单行时限制宽度,多行时限制高度 -->
<view v-if="!isExpanded" class="address-text"
:class="{ 'line-clamp': !isExpanded && lines > 1, 'single-line': !isExpanded && lines === 1 }"
:style="{ '-webkit-line-clamp': lines, '--clamp-lines': lines }">{{ address }}</view>
<!-- 展开后显示的文本 -->
<view v-else class="address-text is-expanded">{{ address }}</view>
<!-- 2. 隐藏的探测层(仅在初始加载时渲染) -->
<!-- 宽度探测:限制宽度为容器可用宽度,用于测高 -->
<view v-if="!isExpanded && !showButton && probeWidth > 0" class="probe-width"
:style="{ width: probeWidth + 'px' }" @change="onProbeHeightChange" id="probe-el">
{{ address }}
</view>
<!-- 展开/收起按钮 -->
<view v-if="showButton" class="toggle-btn" @click="toggleExpand">
{{ isExpanded ? '收起' : '展开' }}
</view>
</view>
</template>
<script>
export default {
name: 'AddressExpand',
props: {
address: {
type: String,
default: ''
},
lines: {
type: Number,
default: 1
}
},
data() {
return {
isExpanded: false,
showButton: false,
probeWidth: 0 // 动态获取的可用宽度
}
},
mounted() {
this.$nextTick(() => {
this.measure();
})
},
methods: {
measure() {
// 第一步:获取组件容器的实际宽度
const query = uni.createSelectorQuery().in(this)
query.select('.address-container').boundingClientRect(container => {
if (!container) return;
// 减去按钮预估宽度 (80rpx) 和文本右边距 (32rpx),得出文本的实际可用宽度
const btnWidth = uni.upx2px(80);
const marginRight = uni.upx2px(32);
// 触发探测层渲染
this.probeWidth = container.width - btnWidth - marginRight;
// 第二步:延迟等待探测层 DOM 渲染完毕,去获取其真实高度
this.$nextTick(() => {
const probeQuery = uni.createSelectorQuery().in(this)
probeQuery.select('#probe-el').boundingClientRect(el => {
if (!el) return;
// 计算单行高度 (fontSize: 28rpx, lineHeight: 1.4)
const lineHeight = uni.upx2px(28) * 1.4;
const maxHeight = lineHeight * this.lines;
// 核心判断:真实高度 > 允许的最大高度 + 0.5px 误差阈值
if (el.height > maxHeight + 0.5) {
this.showButton = true;
}
}).exec()
})
}).exec()
},
toggleExpand() {
this.isExpanded = !this.isExpanded;
if (this.isExpanded) {
this.probeWidth = 0; // 收起探测层
}
}
}
}
</script>
<style scoped>
.address-container {
display: flex;
align-items: flex-end;
margin: 20rpx;
position: relative;
box-sizing: border-box;
}
.address-text {
flex: 1;
font-size: 28rpx;
color: #333;
line-height: 1.4;
word-break: break-all;
}
/* 单行省略样式 */
.single-line {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* 多行省略样式 */
.line-clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
white-space: normal;
}
.is-expanded {
white-space: normal;
display: block;
}
/* 探测层:绝对定位,限制宽度,用于模拟真实文本溢出场景 */
.probe-width {
position: absolute;
left: -9999px;
font-size: 28rpx;
color: transparent;
line-height: 1.4;
white-space: normal;
word-break: break-all;
}
.toggle-btn {
flex-shrink: 0;
font-size: 26rpx;
color: #1296db;
white-space: nowrap;
line-height: 1.4;
margin-top: 0rpx;
}
</style>
引用
javascript
<template>
<view>
<!-- 短地址 -->
<AddressExpand address="广东省深圳市南山区" />
<!-- 长地址 -->
<AddressExpand address="广东省深圳市南山区粤海街道与金融大路交汇保安金融大厦南门101室" />
<!-- 两行省略 -->
<AddressExpand address="广东省深圳市南山区粤海街道与金融大路交汇保安金融大厦南门101室,这里是第二行测试文本,如果超过两行就会显示按钮" :lines="2" />
</view>
</template>
<script>
import AddressExpand from '@/components/AddressExpand/AddressExpand.vue'
export default {
components: {
AddressExpand
}
}
</script>