实习中遇到的说简单也简单,说容易当也不容易,想了蛮久
直接先贴实现效果,
由于是改bug,页面是别人写的,这是我能完成的最终样子,
由于要完成这个搜索的带颜色提示,后端返回的只是单纯的文本,但是要给他颜色的话,就必须要整成html标签加文本的形式,这里采用了一个方法来把它替换成带有颜色的文本。直接来整篇代码
<template>
<div class="list-item pt-23.5px pb-33px w-[calc(100vw-364px-140px)] relative"> // 最外层给了宽度
<div
class="text-22px cursor-pointer"
v-html="title"
@click="searchDetail('/product/detail')"
></div>
<p class="time mt-16px mb-24px text-14px text-[#808080]">{{ item.updateTime }}</p>
<!-- <div class="flex"> -->
<span
class=" content text-16px text-[#606060] "
:class="[flag?'':'test']"
ref ='spanha'
v-html="content"
></span>
<span @click="changeFlag"
v-if="showflag" 这里采用绝对定位来设置最初情况展开的位置,根据自己情况来定位置偏移,
:class="[flag?'':'positi']" 这里flag等于ture时,就不会有绝对定位,就会展现在文本后面
class="text-[#015DAC] text-12px leading-21px h-21px ">{{flag?'收起':'展开'}}
<i class="iconfont icon-icon_sq"
style="font-size:6px"
:class="[flag?'':'xz']">
</i></span>
<!-- </div> -->
</div>
</template>
<script>
export default {
name: 'ListItem',
props: ['item', 'keyword'],
data () {
return {
title: null,
content: null,
flag : false,
searchValue:null,
// 控制展开和收起是否展现
showflag:false
};
},
watch: {
keyword: {
handler (newval) {
this.searchValue = newval;
if (this.item.name) {
this.title = `<p>${this.setValue(this.item.name, newval)}</p>`;
}
if (this.item.comment) {
this.content = `<span class="truncate test">${this.setValue(
this.item.comment,
newval
)}</span>`;
}
},
immediate: true,
},
},
mounted () {
// 获取这个容器的宽度来和文本宽度进行比较,如果是大于的话就得展现
// console.log('获取到了吗',this.$refs.spanha.clientWidth);
// console.log('文本',this.item.comment,this.item.comment.length);
// 由于要展现...号,所以得用块级元素,所以我只能通过判断文本字符数,并且乘以字符个数来比较宽度
// 这里的clientWidth始终是父元素的宽度,因为是块级元素,16是字体大小
if(this.item.comment.length*16>this.$refs.spanha.clientWidth)
{
this.showflag = true;
}
},
methods: {
changeFlag (){
this.flag = !this.flag;
if(this.flag){
this.content = `<span class="truncate2">${this.setValue(
this.item.comment,
this.searchValue
)}</span>`;
}
else{
this.content = `<span class="truncate">${this.setValue(
this.item.comment,
this.searchValue
)}</span>`;
}
},
caseFirstValue (target, value) {
let res = value;
let splitArr = value.split('');
splitArr[0] = splitArr[0].toUpperCase();
res = splitArr.join('');
if (target.indexOf(res) !== -1) {
return [res, true];
}
return [res, false];
},
caseValue (target, value) {
let res = value;
if (target.indexOf(value.toUpperCase()) !== -1) {
res = value.toUpperCase();
return [res, true];
}
if (target.indexOf(value.toLowerCase()) !== -1) {
res = value.toLowerCase();
return [res, true];
}
return [res, false];
},
setValue (target, value) {
let res = target;
let val = value;
if (value) {
const caseFirstRes = this.caseFirstValue(target, value);
const caseRes = this.caseValue(target, value);
val = caseRes[1] ? caseRes[0] : val;
val = caseFirstRes[1] ? caseFirstRes[0] : val;
res = target.replace(val, `<em style="color: #f08300">${val}</em>`);
}
return res;
},
searchDetail (path) {
this.$router.push({ path, query: { id: this.item.id, name: this.item.name } });
},
},
};
</script>
<style lang="less" scoped>
.list-item {
box-shadow: 0px 1px 0px 0px #f0f0f0;
&::marker {
content: "";
}
}
// 这里是把icon进行旋转,那么下箭头就变成了上箭头
.xz{
display: inline-block;
transform: rotate(180deg);
}
// 由于要展现...号,所以得用块级元素,所以我只能通过判断文本字符数,并且乘以字符个数来比较宽度
.test{
white-space: nowrap; /*强制span不换行*/
display:block; /*将span当做块级元素对待*/
overflow: hidden; /*超出宽度部分隐藏*/
text-overflow: ellipsis; /*超出部分以点号代替*/
}
.positi{
position: absolute;
right: -50px;
bottom: 32px;
}
</style>
讲一下核心思想,
<span
class=" content text-16px text-[#606060] "
:class="[flag?'':'test']"
ref ='spanha'
v-html="content"
></span>
可以看到这里就是下面展现的内容,由于是有html标签,所以是要用v-html来展示,
多次用到绑定样式的思想,以及通过flag来判断是否展现,最主要的是通过文字长度*文字大小来和容器宽度比较,如果大于容器宽度就说明多于一行,就得展现展开和收起,这里其实并不完美,完美的是要把展开也放在下划线里面的位置,不知道还会不会给我提bug,我心累!
我也看了很多方法,但是情景都不是特别符合,只好自己摸索了,菜是原罪。