废话不多说,先看效果
布局的话是分成左右两侧,主要用到的是小程序的scroll-view组件中的scroll-into-view
和bindscroll
wxml代码
catchscroll换成bindscroll也可以的
<view class="main-container">
<!-- 左侧滚动list -->
<scroll-view
wx:if="{{onsearch === false}}"
class='list-left'
enhanced='true'
show-scrollbar='false'
scroll-into-view="{{id}}"
scroll-y='true'
data-record="{{highlight}}"
catchscroll='scrollView'
bindscrolltolower='scrollBottom'
>
<view id="hot">
<!-- 推荐车型 -->
<view class="recommend-container">
<view class="each-recommend-style" wx:for="{{recommendList}}" wx:for-item="caritem" wx:key='index' data-record="{{caritem}}" catchtap="clickCar">
<image style="position: absolute;width:72rpx;height:72rpx" src="{{caritem.img}}"></image>
</view>
</view>
</view>
<!-- 车型list -->
<block wx:for="{{naviList}}" wx:if="{{item!='hot'}}" wx:key="index">
<view class="left-item" >
<view id="{{item}}">
<view style="position: sticky;top: 0;z-index: 10;background: #ECECEC;height:48rpx;padding-top:16rpx">{{item}}</view>
<view class="brand-line" wx:for="{{carlist[item]}}" wx:for-item="caritem" wx:key="index" data-record="{{caritem}}" catchtap="clickCar">
<block>
<image wx:if="{{caritem.img}}" style="width:80rpx;height:80rpx;margin-right:40rpx" src="{{caritem.img}}"></image>
<view wx:else class="none-img">none</view>
</block>
{{caritem.name}}
</view>
</view>
</view>
</block>
</scroll-view>
<!-- 右侧导航 -->
<view wx:if="{{onsearch === false}}" class="right-navi-container">
<view class="right-navi-item" wx:for="{{naviList}}" wx:key='index' style="{{item===highlight?'background:#1890ff':''}};{{item===highlight?'color:#FFF':''}}" data-record='{{item}}' catchtouchend="touchEnd" catchtouchstart="touchStart" catchtouchmove="touchMoveNavi">
<view class="navi-hover" wx:if="{{hoverText && hoverText === item}}">{{hoverText}}</view>
{{item==='hot'?'选':item}}
</view>
</view>
</view>
wxss代码
/* pages/addCar/addCar.wxss */
.main-container{
position: fixed;
width: 100vw;
height: 100vh;
background:#ECECEC
}
.list-left{
margin-top: 130rpx;
width: 100vw;
height: calc(100vh - 130rpx);
z-index: -1;
background:#ECECEC
}
.left-item{
padding: 0 50rpx 0 40rpx;
}
.brand-line{
display: flex;
align-items: center;
padding: 20rpx 24rpx;
color: #666666;
background: #FFF;
}
.none-img{
width: 80rpx;
height: 80rpx;
margin-right: 40rpx;
text-align: center;
border: 2px solid #ECECEC;
border-radius: 50%;
font-size: 34rpx;
line-height: 80rpx;
color: #ECECEC;
}
.right-navi-container{
display: flex;
flex-direction: column;
position: fixed;
right: 12rpx;
top: 130rpx;
font-size: 12rpx;
z-index: 999;
}
.right-navi-item{
position: relative;
width: 28rpx;
height: 28rpx;
margin-top: 6rpx;
text-align: center;
font-size: 22rpx;
font-family: PingFang SC, PingFang SC-Regular;
font-weight: bold;
color:#666666;
line-height: 28rpx;
border-radius: 20rpx;
}
.navi-hover{
position: absolute;
font-size: 40rpx;
font-weight: bold;
color: #FFF;
top: -30rpx;
right: 50rpx;
width: 100rpx;
height: 100rpx;
text-align: center;
line-height: 100rpx;
border-radius: 50rpx;
background: #1890ff90;
}
js代码
后台给我返回的数据截图是这样的,所以我处理起来比较方便
// pages/addCar/addCar.js
const app = getApp();
const Util = require('../../utils/util.js')
let hostN = "https://xxxxxxx.com"
const { imageProPath } = require('../../utils/imageUrlUtil.js')
Page({
/**
* 页面的初始数据
*/
data: {
imagePath: imageProPath,
placeholder:' 请输入车辆品牌 ',
inputValue:'',//搜索值
onsearch:false,
searchResult:[],//搜索结果
searchcarlist:[],//所有品牌数组
recommendList:[],//热门品牌数组
id: 'hot',//需要滑动到的ID
highlight: 'hot',//当前高亮字母
hoverText: '',//手指放拖动Navi时左侧显示的气泡
naviList:['hot','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'],//Navi数组
carlist:{},//所有品牌按类型分类对象
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
this.initBrand();
},
/**
* 初始化品牌数据
*/
//初始化车辆品牌
async initBrand(){
try {
wx.showLoading({
title: '加载中',
})
let {data} = await Util.httpRequest({
url: `${hostN}/car/getCarBrands`,
method: 'get',
})
if(data.code === 10200){
this.setData({
carlist : data.data.allBrands,
recommendList :data.data.hotBrands
})
}
wx.hideLoading({
success: (res) => {},
})
} catch (error) {
wx.showToast({
title: error.errMsg,
icon:'none'
})
wx.hideLoading({
success: (res) => {},
})
}
},
/**
* 滑动触发(设置右侧导航高亮)
*/
scrollView(e){
let that = this;
this.data.naviList.forEach(item => {
console.log(item)
wx.createSelectorQuery().select(`#${item}`).boundingClientRect(function(rect){
if(-rect.top<=rect.height && (rect.bottom-71)>0 && rect.bottom <= (rect.height+71)){
that.setData({
highlight:rect.id
})
}else{}
}).exec()
});
},
/**
* 点击搜索栏触发
*/
onfocus(e){
this.setData({
placeholder: ''
})
let searchcarlist = []
for (const key in this.data.carlist) {
if (this.data.carlist.hasOwnProperty(key)) {
const element = this.data.carlist[key];
searchcarlist = searchcarlist.concat(element)
}
}
this.setData({
searchcarlist: searchcarlist
})
},
/**
* 取消搜索触发
*/
cancelInput(){
this.setData({
onsearch : false,
inputValue: '' ,
placeholder:' 请输入车辆品牌 ',
})
},
/**
* 搜索时触发
*/
input(e){
let inputvalue = e
if(inputvalue.detail.value === ''){
this.setData({
searchResult: []
})
return
}
let rep = new RegExp(inputvalue.detail.value)
let fiterText = this.data.searchcarlist.filter((e)=>{
return rep.test(e.name)
})
this.setData({
searchResult: fiterText
})
},
/**
* 用手指在右侧导航栏滑动时触发
*/
touchStart(e){
console.log(e.currentTarget.dataset)
this.setData({
id:e.currentTarget.dataset.record,
})
},
touchEnd(e){
this.setData({
hoverText:'',
})
},
touchMoveNavi(e){
if(e.changedTouches[0].clientY<=50 || e.changedTouches[0].clientY>=505){
this.setData({
hoverText:'',
})
return
}
this.setData({
id:this.data.naviList[Math.floor((e.changedTouches[0].clientY-65)/18)],
hoverText:this.data.naviList[Math.floor((e.changedTouches[0].clientY-65)/18)],
})
}
})