封装原因
在项目中会出现处理文本展示的需求:内容过多就超过多少行就隐藏,但是需要可以点击展开查看完整内容、可以点击收起隐藏完整内容
第一种:文字类型
第二种图标类型
可选参数
| 组件参数 | 说明 | 可选值 |
|---|---|---|
| text | 展示的文本内容(必传) | 字符串 |
| rows | 文本多少行隐藏 | 字符串 |
| textStyle | 文本的样式 | 对象 |
| labelStyle | 展开收起文本、图标的样式 | 对象 |
| hideText | 自定义收起的文字 | 字符串 |
| showText | 自定义展开的文字 | 字符串 |
| labelIcon | 自定义展开收起的图标的路径 | 字符串(可以是本地也可以是网络路径) |
注意:
- labelStyle里面不能传文字的相关样式,例如font-size字号/line-height行高/font-weight粗细/font-family字体,因为我需要让展开收起的文本的样式与展示的文本内容的样式一致
- 如果不想出现展开收起的元素,可以给labelStyle传入属性:display: 'none'
代码
<template>
<div class="box">
<!-- 文本内容 -->
<text class="text-all" :style="[{ opacity: textHeight ? 1 : 0 }, textStyle]">
{{ props.text }}
</text>
<!-- 占位文本 -->
<text class="placeholder" :style="props.textStyle">{{ placeholder }}</text>
<!-- 展开收起文本/按钮 -->
<view
class="label-box"
:style="[{ 'justify-content': showAll ? 'flex-end' : 'space-between' }, lableBoxStyle]"
v-if="lines > rows"
>
<text :style="props.textStyle">{{ showAll ? '' : '...' }}</text>
<image
@click="showText"
v-if="props.labelIcon"
:src="props.labelIcon"
mode=""
:style="[{ transform: 'rotate(' + (showAll ? 180 : 0) + 'deg)' }, labelStyle]"
/>
<view v-else @click="showText" :style="[props.textStyle, labelStyle, { height: '100%' }]">
{{ showAll ? props.hideText : props.showText }}
</view>
</view>
</div>
</template>
<script setup>
import { ref, onMounted, computed, watch, getCurrentInstance, nextTick } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
const { proxy } = getCurrentInstance();
const example = proxy;
const props = defineProps({
text: {
type: String,
required: true,
},
rows: {
type: String,
default: '2',
},
textStyle: {
type: Object,
default: {},
},
labelStyle: {
type: Object,
default: {},
},
hideText: {
type: String,
default: '收起',
},
showText: {
type: String,
default: '更多',
},
labelIcon: {
type: String,
default: '',
},
});
onMounted(() => {
init();
});
let textStyle = ref(''); // 文本样式
let lableBoxStyle = ref({}); // lableBox样式
let labelStyle = ref({}); // label样式
let placeholder = ref('占');
let rows = ref(''); // 行数
let showAll = ref(false); // 是否显示全部内容 true 显示所有内容 false 只显示指定行数内容
let lineHeight = ref(0); // 单行文本高度
let textHeight = ref(0); // 文本高度
let oneTextWidth = ref(0); // 单个文字宽度
async function init() {
rows.value = props.rows * 1;
textStyle.value = {
overflow: 'hidden',
transition: 'all 0.3s',
...props.textStyle,
};
labelStyle.value = {
...props.labelStyle,
};
if (!props.labelIcon) {
// 删除labelStyle中的字号/行高/粗细/字体(与文字样式保持一致)
for (let key in labelStyle.value) {
if (
key == 'fontSize' ||
key == 'font-size' ||
key == 'lineHeight' ||
key == 'line-height' ||
key == 'fontWeight' ||
key == 'font-weight' ||
key == 'fontFamily' ||
key == 'font-family'
) {
delete labelStyle.value[key];
}
}
}
await getlineHeight();
textStyle.value.height = lineHeight.value * rows.value + 'px';
lableBoxStyle.value.height = lineHeight.value + 'px';
placeholder.value = '';
await getTextHeight();
if (lines.value > rows.value) {
let labelBoxWidth = await getLableBoxWidth();
lableBoxStyle.value.width =
Math.ceil(labelBoxWidth / oneTextWidth.value) * oneTextWidth.value + 'px';
}
}
// 获取单行文本高度/单个文字宽度
function getlineHeight() {
let query = uni.createSelectorQuery().in(example);
return new Promise((resolve, reject) => {
query
.select('.placeholder')
.fields(
{
size: true,
},
(data) => {
lineHeight.value = data.height;
oneTextWidth.value = data.width;
resolve();
}
)
.exec();
});
}
// 获取文本展示高度
function getTextHeight() {
let query = uni.createSelectorQuery().in(example);
return new Promise((resolve, reject) => {
query
.select('.text-all')
.fields(
{
size: true,
},
(data) => {
textHeight.value = data.height;
resolve();
}
)
.exec();
});
}
// 获取右侧lableBox的宽度
function getLableBoxWidth() {
let query = uni.createSelectorQuery().in(example);
return new Promise((resolve, reject) => {
query
.select('.label-box')
.fields(
{
size: true,
},
(data) => {
let width = Math.ceil(data.width);
resolve(width);
}
)
.exec();
});
}
// 文本所占总行数
let lines = computed(() => {
return Math.floor(
textHeight.value > 0 && lineHeight.value > 0 ? textHeight.value / lineHeight.value : 0
);
});
// 展示隐藏查看更多
function showText() {
showAll.value = !showAll.value;
if (showAll.value) {
textStyle.value.height = textHeight.value + 'px';
} else {
textStyle.value.height = lineHeight.value * rows.value + 'px';
}
}
</script>
<style lang="scss" scoped>
.box {
position: relative;
text {
display: -webkit-box;
text-align: justify;
}
.placeholder {
position: absolute;
left: 0;
top: 0;
transform: translateX(-500%);
z-index: -1;
opacity: 0;
}
.label-box {
position: absolute;
bottom: 0;
right: 0;
background: #fff;
display: flex;
align-items: center;
image {
margin-left: 10rpx;
}
}
}
</style>
页面使用
<hideText
:text="text"
rows="2"
:labelStyle="{
background: '#000',
padding: '5rpx 10rpx',
'border-radius': '6rpx',
display: 'flex',
'justify-content': 'center',
'align-items': 'center',
}"
></hideText>