1.html代码:
<template>
<view class="classicsBox">
<scroll-view class="classics-left" scroll-y="true" scroll-with-animation :scroll-into-view="clickId">
<view v-for="(item,index) in contentData" :key="item.id" :id="item.id" class="classics-left-item" :class="picked==index?'checkedStyle':''" @click="selectActiveEvt(item)">
{{item.title}}
</view>
</scroll-view>
<!-- :scroll-top="scrollRightTop" -->
<scroll-view scroll-y="true" :scroll-into-view="clickId" :scroll-anchoring="true" scroll-with-animation class="classics-right" @scroll="scrollEvt">
<view class="classics-right-item" v-for="item in contentData" :key="item.id" :id="item.id">
<view class="title">
{{item.title}}
</view>
<view class="item-box" v-for="it in item.content">
<img class="item-box-left" :src="it.img" alt="">
<view class="item-box-right">
<view class="item-box-right-name">
{{it.name}}
</view>
<view class="item-box-right-describe">
{{it.desc}}
</view>
<view class="item-box-right-buy">
<view class="item-box-right-price">
¥{{it.price}}
</view>
<view class="item-box-right-pick">
选规格
</view>
</view>
</view>
</view>
</view>
</scroll-view>
</view>
</template>
2.script代码
<script>
export default {
components: {},
data() {
return {
contentData:[{
id:'tab1',
title:'热销专区',
content:[
{id:101,img:'static/rexiao1.png',name:'郁金香',desc:'花语',price:'99',},
{id:102,img:'static/rexiao2.png',name:'郁金香',desc:'花语',price:'99',},
]
},
{
id:'tab2',
title:'生日鲜花',
content:[
{id:201,img:'static/shengri1.png',name:'郁金香',desc:'花语',price:'99',},
{id:202,img:'static/shengri2.png',name:'郁金香',desc:'花语',price:'99',},
]
},......],//列表数据
clickId:'tab1', //点击选项的id
picked:0, // 左侧选中选项的index
nowRightIndex:0, // 右边当前滚动的index
itemArr:[], //用于存放右侧item位置数据
scrollRightTop:0,
timer:null,
}
},
methods: {
// 左侧切换点击事件
selectActiveEvt(e) {
this.clickId = e.id;
this.picked = this.contentData.findIndex(it=>it.id==e.id);
},
scrollEvt(e){
// 防抖
if(this.timer){
clearTimeout(this.timer);
}
this.timer = setTimeout(()=>{
this.nowRightIndex = this.itemArr.findLastIndex(it=>e.detail.scrollTop>=(it.bottom-228))+1; //判断当前顶部是处于哪个item,获取当前item的index
if(this.nowRightIndex==-1) this.nowRightIndex=0;
if(this.nowRightIndex==this.picked) return;
this.clickId = this.contentData[this.nowRightIndex].id;
this.picked = this.nowRightIndex;
},500);
},
// 计算右侧每个item到顶部的距离,存放到数组
getItemDistence(){
new Promise(resolve=>{
let selectQuery = uni.createSelectorQuery().in(this);
selectQuery.selectAll('.classics-right-item').boundingClientRect(rect=>{
if(!rect.length){
setTimeout(()=>{
this.getItemDistence();
},10);
return;
}
rect.forEach(it=>{
this.itemArr.push(it); // 这里获取到的数据是每个item距离页面顶部的数据,以及每个item的自身数据
resolve();
})
}).exec()
})
},
},
mounted(){
// 设置一个延时,确保所有dom和样式加载完成,否则拿到的数据可能有误
setTimeout(()=>{
this.getItemDistence();
},500)
},
}
</script>
3.css样式
.sortBox{
height: 100%;
width: 100%;
box-sizing: border-box;
/* padding: 12px; */
padding-bottom: 0;
position: relative;
}
.boxTop{
width: 100%;
position: fixed;
top: 44px;
left: 0;
height: 220px;
}
.sort-search{
height: 50px;
display: flex;
justify-content: space-between;
padding: 12px;
padding-bottom: 0;
box-sizing: border-box;
}
.sort-search-left{
box-sizing: border-box;
width: 100px;
height: 38px;
line-height: 38px;
border-radius: 16px;
border: 1px solid #f0f0f0;
text-align: right;
padding: 0 10px;
background: url('../../static/ping.png') left center no-repeat;
background-size: 45%;
}
.sort-search-right{
width: 36px;
height: 100%;
margin-right: 80px;
border: #f0f0f0 1px solid;
border-radius: 19px;
text-align: center;
line-height: 36px;
}
.sort-collect{
margin-top: 15px;
}
.sort-broadcast{
width: 100%;
height: 30px;
background-color: #fff7fa;
display: flex;
font-size: 18px;
line-height: 30px;
padding: 0 10px;
box-sizing: border-box;
font-weight: bold;
}
.sort-type{
display: flex;
height: 60px;
box-sizing: border-box;
align-items: flex-end;
justify-content: space-evenly;
font-size: 16px;
font-weight: bold;
color: #909090;
}
.sort-type-item{
display: flex;
align-items: center;
height: 40px;
}
.sort-type-item-img{
height: 30px;
margin-right: 6px;
}
.sort-type-item-text{
height: 100%;
line-height: 40px;
}
.sort-type-item-text-checked{
border-bottom: #ff9092 3px solid;
color: #41414d;
}
.opcity{
opacity: 0;
}
.sortBox-scoll{
position: absolute;
top: 220px;
left: 0;
width: 100%;
background-color: #f0f0f0;
height: calc(100vh - 314px);
overflow-y: auto;
}