实现效果:左边点击西餐,右边会滚动至西餐置顶区域;右边滚动到西餐区域,左边西餐会是选中状态
知识点:
scroll-view
1):scroll-into-view="clickId"
: 值应为某子元素(标题的)id(id不能以数字开头)。滚动到该元素
配套的:动态设置标题的id<view class="title" :id="'po'+index">{{item.title}}</view>
2)scroll-with-animation
: 滚动带有动画,不至于效果太生硬
3)@scroll="scroll"
: 滚动触发事件
4)@scrolltolower="scrolltolower"
:滚动至底部触发事件
5)使用scroll-view
,是纵向滚动,需设置高度<scroll-view style="white-space: nowrap;height: 400rpx;">
知识点:
uni.createSelectorQuery()
返回SelectorQuery
对象实例,使用select
等方法选择节点,并使用boundingClientRect
等方法选择需要查询的信息
SelectorQuery
:查询节点信息的对象
SelectorQuery().in
:将选择器的选取范围更改为自定义组件component
内,返回一个SelectorQuery
对象实例。(初始时,选择器仅选取页面范围的节点,不会选取任何自定义组件中的节点)
<template>
<view class="m-conatiner">
<view class="left">
<view :class="{activeClass:currentIndex == index}" v-for="(item,index) in list" :key="index" @click="setId(index)">{{item.title}}</view>
</view>
<view class="right">
<scroll-view scroll-y="true" :scroll-into-view="clickId" scroll-with-animation @scroll="scroll" @scrolltolower="scrolltolower" style="white-space: nowrap;height: 400rpx;" >
<view v-for="(item, index) in list" :key="index">
<view class="title" :id="'po'+index">{{item.title}}</view>
<view v-for="(it,idx) in item.alist" :key="idx">{{it}}</view>
</view>
</scroll-view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
title: 'Hello',
list: [
{title:'中餐',alist: ['馒头','包子','盖饭','炒面','饺子','鸡排饭']},
{title:'西餐',alist: ['牛排','意大利面','披萨','汉堡']},
{title:'法餐',alist: ['鹅肝1','鹅肝2','鹅肝3','鹅肝4','鹅肝5','鹅肝6','鹅肝7','鹅肝8','鹅肝9','鹅肝10']}
],
clickId: '',
currentIndex: '',
topList: []
}
},
onLoad() {
},
onReady(){
this.getNodeInfo();
},
methods: {
setId(index) { // 点击左边标题 触发事件 动态改变左边标题的id;
this.clickId = 'po'+index;
this.currentIndex = index;
},
scroll(e) { // 右边滚动触发事件 获取每个标题间的距离,判断滚动的高度在哪个区间内
let scrollTop = e.target.scrollTop+1;
for(let i=0; i<this.topList.length; i++) {
const h1 = this.topList[i];
let h2 = this.topList[i+1];
if (scrollTop >= h1 && scrollTop < h2){
this.currentIndex = i;
}
}
},
scrolltolower(){ // 滚动到底部触发
setTimeout(()=> {
this.currentIndex = this.list.length -1;
},80)
},
getNodeInfo(){ // 获取DOM 取得每个标题间的高度。exec执行
const query = uni.createSelectorQuery().in(this);
query.selectAll('.title').boundingClientRect(data => {
console.log("得到布局位置信息",data,);
let arr = [];
data.map(item=>{
arr.push(item.top)
})
this.topList = arr;
}).exec();
}
}
}
</script>
<style lang="scss">
.m-conatiner{
width: 100%;
height: 400rpx;
border: 2rpx solid #ddd;
display: flex;
justify-content: space-between;
align-items: center;
box-sizing: border-box;
}
.left{
flex: 0 0 200rpx;
height: 100%;
border: 2rpx solid red;
.activeClass{
background: pink;
}
}
.right{
flex: 1;
height: 100%;
border: 2rpx solid red;
.title{
font-size: 40rpx;
font-weight: bold;
background: pink;
}
}
</style>