最近在做小程序项目的时候遇到了索引栏功能的东西,该项目是选择车型的需求。先看效果图:
实现上面的功能大概有自定义弹框、点击索引字母跳转到对应的位置、搜索关键字高亮等。下面一个个来实现。
特别说明:刚开始看到这种索引栏组件,就想到了使用vant的indexBar组件,但是后面使用popup组件indexBar共用的时候,点击索引字母是失效的,原因是因为popup的弹出层需要定位导致跳转对应的字母位置失效,很坑!!
<!-- 蒙层 -->
<view class="remark" wx:if="{{showBrand}}" bindtap="closeBrand" catchtouchmove="preventTouchMove"></view>
<!-- 内容 -->
<view class="re-con" wx:if="{{showBrand}}">
<view class="cityBox" wx:if="carBrandList">
<view class="search-city">
<view class="search-con">
<icon class="iconfont icon-fangdajing" bindtap="searchKey"></icon>
<input placeholder="请输入车型搜索" type="text" value="{{searchValue}}" bindinput="getCity"/>
</view>
</view>
<view class="content">
<view class="all-city">
<scroll-view class="city-scroll {{isFirstId?'':'city-scoll-height'}}" scroll-y="true" scroll-with-animation="true" scroll-into-view="{{toView}}">
<view class="city-list" wx:if="{{!searchList.length}}">
<!-- 循环城市列表 start -->
<view wx:for="{{carBrandList}}" wx:key="index" id="{{'city'+index}}" catchtap='selectcity' data-initial="{{item.initial}}" class="listGroup">
<!-- 字母导航 -->
<view class="nav-text">
<text class="{{index==currentInitial?'currentClass':''}}">{{item.initial}}</text>
</view>
<!-- 汽车一级品牌名字 -->
<view class="show-city">
<radio-group class="radio-group" bindchange="radioChange" wx:if="{{!isFirstId}}">
<view class="city-item" wx:for="{{item.carBrandInfoList}}" wx:key="index" data-name="{{item.name}}" data-vendorid="{{item.parentId}}" data-obj="{{item}}" bindtap="clickFirstId">
<label for="{{item.carModelId}}">
<image src="{{item.logo}}"></image>
<text class="text">{{item.name}}</text>
</label>
<radio class="radio" id="{{item.carModelId}}" hidden="{{car.carModelId!=item.recordId}}" value="{{item.name}}" checked="{{car.carModelId==item.recordId}}" color="#28b8ff"></radio>
</view>
</radio-group>
<block wx:else>
<view class="city-item" wx:for="{{item.carBrandInfoList}}" wx:key="index" data-name="{{item.name}}" data-obj="{{item}}" bindtap="clickFirstId">
<image src="{{item.logo}}"></image>
<text>{{item.name}}</text>
</view>
</block>
</view>
</view>
<!-- 循环城市列表 end -->
</view>
<!-- 关键词搜索的列表 -->
<view class="city-list" wx:if="{{searchList.length}}">
<view wx:for="{{searchList}}" wx:key="index" id="{{'city'+index}}" catchtap='selectcity' data-initial="{{item.initial}}">
<view class="show-city">
<radio-group class="radio-group" bindchange="radioChange">
<view class="city-item" data-name="{{item.fullName}}" data-vendorid="{{item.vendorId}}" data-obj="{{item}}" bindtap="clickFirstId">
<label for="{{item.recordId}}">
<!-- <text >{{item.fullName}}</text> -->
<text wx:for="{{item.fullName}}" wx:key="index" class="{{item == searchValue? 'currentClass' : '' }}">{{item}}</text>
</label>
<radio class="radio" id="{{item.recordId}}" hidden="{{car.carModelId!=item.recordId}}" value="{{item.fullName}}" checked="{{car.carModelId==item.recordId}}" color="#28b8ff"></radio>
</view>
</radio-group>
</view>
</view>
</view>
</scroll-view>
</view>
<!-- 字母索引 start -->
<view class="search-nav" wx:if="{{isFirstId&&!searchList.length}}">
<text bindtap="cityScroll" data-initial="{{item.initial}}" data-index="{{index}}" wx:for="{{carBrandList}}" wx:key="index" class="navlist {{index==currentInitial?'currentClass':''}}" catchtouchmove="preventTouchMove">{{item.nav}}</text>
</view>
<!-- 字母索引 end -->
</view>
</view>
<!-- 取消确定 -->
<view class="foot-btn" wx:if="{{!isFirstId}}">
<view>
<view class="cancel" bindtap="clickReset">重置</view>
<view class="comfir" bindtap="clickComfir">确认</view>
</view>
</view>
</view>
1、点击右边索引字母实现跳转到对应的位置
// 点击英文字母进行跳转到相应位置
cityScroll(e) {
let data = this.data.carBrandList
let Index = e.currentTarget.dataset.index
let initial = data[Index].initial
console.log(initial)
if (data.length) {
data.map((res, index) => {
if (initial == res.initial) {
this.setData({
currentInitial: index,
toView: `city${index}`//用于定位
})
}
})
}
wx.showToast({
title: initial,
icon: 'none'
})
},
上面的toView是利用小程序的scroll-view组件的scroll-into-view属性(值应为某子元素id(id不能以数字开头)。设置哪个方向可滚动,则在哪个方向滚动到该元素)将每一块的车型(首字母为A的为一块)的顶层元素设置一个id,对应上面绑定的id="{{‘city’+index}}" 点击的时候可以获取到当前的index,然后实现跳转。
2、搜索关键词高亮
//搜索关键词
searchKey() {
this.setData({
isFirstId: false
})
if (this.data.searchValue) {
netRequest.webRequest(getApi.getKeyWords, {
keyWords: this.data.searchValue
}, "get").then(res => {
let data = res.data
if (data.length) {
data.map(item => {
item.fullName = this.getSpit(item.fullName, item.brandName)
})
this.setData({
searchList: data
})
this.searchTap()
}
})
} else {
this.setData({
searchList: '',
carBrandList: this.data.copyBrand,
isFirstId: true
})
}
},
//处理关键词高亮
searchTap: function() {
var that = this;
that.setData({
listDataCopy: that.data.searchList//搜索关键词后台返回的搜索列表
})
var data = that.data.searchList;
var newData = that.data.listDataCopy;
for (var i = 0; i < data.length; i++) {
var dic = data[i]
var newDic = newData[i]
var fullName = dic["fullName"]
newDic["fullName"] = this.getInf(fullName, that.data.searchValue);
}
that.setData({
searchList: newData,
})
console.log(this.data.searchList)
},
//整理关键词
getInf(str, key) {
return str.toString().replace(new RegExp(`${key}`, 'g'), `%%${key}%%`).split('%%')
},
实现思路:首先根据关键词去获取后台返回的搜索值列表,然后遍历这个数组,拿到需要展示的属性,例子是fullName,将搜索关键词与遍历的fullName传入getInf函数,该函数实现在fullName中找到(fullName中一定有关键词字符串,因为是根据关键词搜索出来的值)找到之后将fullName分隔开,如fluuName=“宝马X5M”,关键词为“宝马”,那么getInf返回的是["",“宝马”,“X5M”]的数组,然后在界面遍历这个数组,并且遍历的item如果跟搜索值"宝马"相同那么添加高亮的calss,上例为数组的第二个(下标为1)会添加高亮的calss,从而实现关键词“宝马”高亮的效果。
实现手指滑动右侧的索引字母列表跳转到对应的位置
本项目因为scroll-view组件的原因,存在动画延迟跳转所以为实现这个功能。可以参考以下思路:
想要手指滑动索引跳转到对应位置需要计算每一块的高度,并获取计算出,触摸的pageY和触摸时的一直变化的pageY的差值/每个索引元素的高度,代码如下:
//获取每一项组合的高度(根据首字母分组)
calculateHeight() {
let that = this
const query = wx.createSelectorQuery()
const list = query.selectAll('.listGroup')
if (this.data.isFirstId) {
const height = query.select('.navlist')
//获取第一个字母索引元素的高度
height.boundingClientRect(function(rect) {
that.setData({
height: rect.height
})
}).exec()
}
let arr = []
list.boundingClientRect(function(rect) {
if (rect.length) {
rect.map(res => {
arr.push(res.height)
})
that.setData({
listHeight: arr
})
console.log(arr)
}
}).exec()
},
上图的wx.createSelectorQuery是小程序自带获取demo元素的api,传送门=>boundingClientRect
该api可以直接获取元素的高度、宽度、left、right、top、bottom等等信息。
划水结束。趁空闲时间写的,有点赶,如有错误请联系我!本人微信:huang009516