搜索的时候记录用户搜索历史,开始为了开发方便固定了每个搜索项的宽度,每行固定展示几项,类似下图:
但这样虽然开发简单但用户体验肯定不好,如果搜索项比较短的话显示尚且完整,若搜索内容略长,就完全看不出自己之前搜索的是什么。
现在要将其改为自适应长度,搜索项最多占用一行,超出一行部分省略,一般情况也不会超出一行。然后当按钮所占行数超过两行则自动隐藏超出部分,显示折叠按钮,可以点开或者折叠超出部分。
难点在于,因为搜索项是自适应长度,你无法判断每一行会展示几个搜索项,也无法判断折叠点按钮放在哪一项之后。
这个需求在京东上体验效果最好,但京东是右侧额外提供了一段空白用来安放折叠按钮,视觉上不太舒服。
淘宝的实现是基于js,先展示出所有的搜索项,然后js判断,超出后进行折叠,视觉上差不多了,但是打开搜索页面会很明显的先看到所有的搜索项,然后自动折叠隐藏,用户体验略差。
接下来提供下项目中遇到这个需求我的实现方式。
主要要解决的问题:
1. 搜索项根据文本自适应宽度
2. 每一行不在控制展示多少项
3. 要判断是否超出两行,超出两行则进行折叠
4. 保证折叠按钮不管展开还是收缩都要跟在最后一个搜索项后
首先,自适应宽度比较简单,不指定搜索项宽度,提供padding来使长度自适应
display: inline-block;
align-items: center;
border-radius: 1rem;
box-sizing: border-box;
height: 0.56rem;
line-height: 0.56rem;
margin-bottom: 0.24rem;
text-align: center;
padding: 0 0.28rem;
font-size: 0.24rem;
color: #666;
background-color: #F6F7FA;
margin-right: .2rem;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 100%;
其中这段代码主要为了长度超出截断展示省略号,并限制每一项长度最多不超过一行
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 100%;
然后,要判断整体内容的高度是否超过了两行,可以通过获取容器的高度来实现,但这里并不采用这种方式。
采用的方式是js获取父容器所有的子节点,然后进行遍历操作,根据子节点的offsetLeft属性进行判断,因为最左边的那个节点的offsetLeft永远是0,所以可以判断出现了几行,先上代码:
/**
* @description 历史记录 页面超出两行截取数据
*/
toggleHistoryData() {
let idx = 0
let count = 0
this.$nextTick(() => {
let ulChid = document.querySelector('.history-content').childNodes//获取父容器所有子节点
ulChid.forEach((i, index) => {
console.log(i + ':', i.offsetLeft)
if (i.offsetLeft === 0) {
count++
if (count === 3) {
idx = index - 1
this.hasMoreBtn = true
}
}
})
// 超过2行截断数据
if (idx > 0) {
this.historySearchListShow = this.historySearchList.slice(0, idx)
} else {
this.historySearchListShow = this.historySearchList
}
})
},
这里会先便利容器的所有子节点,每出现一个offsetLeft=0,代表出现了一个新行,若出现第三个offsetLeft=0则代表超出两行,显示折叠按钮,并且获取第三个offsetleft=0前一个节点的索引。
最后截断数据源使搜索项不超出两行,这里注意的是,实际返回的数据是满两行的数据但去掉第二行的最后一个,因为这里要放一个折叠按钮。
这样的话就可以在布局的时候直接把折叠按钮放在搜索项的末尾,只是控制展示与否,如下
<ul :class="{'history-content':true,'history-hide':!showMore}" v-if="historySearchList.length">
<li class="van-ellipsis" v-for="(item, index) in historySearchListShow" :key="index" @click="doHistorySearch(item)">{
{
item }}</li>
<span class="icon-more" v-if="!showMore && hasMoreBtn" @click="toggleShowMore"></span>
<span class="icon-more-hide" v-if="showMore && hasMoreBtn" @click="toggleShowMore"></span>
</ul>
这里可能会有疑问,如果第一次把数据截断展示,那第二次判断的时候实际不是拿全部的数据做判断二是阶段后的肯定不满两行的数据。
其实这里,当首次加载是肯定没有问题,然后页面中第一次点折叠按钮他会走不满两行的逻辑,这里会把全部的数据重新付给展示给前端的字段,这样保证当再次折叠时,实际还是基于完整的数据进行判断的。
目前只知道淘宝也是基于js实现的,但不了解他的实现方式。这种实现方式虽然也是先展示全部数据再折叠,但明显效率要高于淘宝,并且同时没有京东末尾空白的问题。