一、需求
scroll-view实现内容滚动时, 标题也滚动
二、效果
三、代码实现
c
<template>
<view class="content">
<view class="head">头部固定区域</view>
<view class="list_box">
<!-- 菜单左边 -->
<view class="left">
<scroll-view scroll-y="true" class="scroll">
<view class="item" v-for="(item,index) in leftArray" :key="index"
:class="{ 'active':index==leftIndex }" :data-index="index" @tap="leftTap">{{item.id}}</view>
</scroll-view>
</view>
<!-- 右侧内容部分 -->
<view class="main">
<scroll-view scroll-y="true" @scroll="mainScroll" class="scroll" :scroll-into-view="scrollInto"
:scroll-with-animation="true" @touchstart="mainTouch" id="scroll-el">
<block v-for="(item,index) in mainArray" :key="index">
<scroll-view class="right-scroll" :id="'item-'+index">
<!-- :scroll-x="true" 加上可以横向滑动 -->
<block v-for="(item2,index2) in item.list" :key="index2">
<view class="item">
<view class="goods">
<view>左边是第{{ index + 1 }}个</view>
<view>右边是第{{ index2+1 }}个</view>
</view>
</view>
</block>
</scroll-view>
</block>
</scroll-view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
leftArray: [{
id: 1
},
{
id: 2
},
{
id: 3
},
{
id: 4
},
{
id: 5
},
{
id: 6
},
{
id: 7
},
{
id: 8
},
],
mainArray: [],
topArr: [],
leftIndex: 0,
isMainScroll: false,
scrollInto: ''
}
},
mounted() {
this.getListData();
},
methods: {
/* 获取列表数据 */
getListData() {
/* 因无真实数据,当前方法模拟数据 */
let [left, main] = [
[],
[]
];
for (let i = 0; i < 8; i++) {
left.push(`${i+1}类商品`);
let list = [];
for (let j = 0; j < (i + 1); j++) {
list.push(j);
}
main.push({
title: `第${i+1}类商品标题`,
list
})
}
this.mainArray = main;
this.$nextTick(() => {
setTimeout(() => {
this.getElementTop();
}, 10)
});
},
//获取距离顶部的高度
getScrollTop(selector) {
return new Promise((resolve, reject) => {
let query = uni.createSelectorQuery().in(this);
query.select(selector).boundingClientRect(data => {
resolve(data.top)
}).exec();
})
},
/* 获取元素顶部信息 */
async getElementTop() {
/* Promise 对象数组 */
let p_arr = [];
/* 遍历数据,创建相应的 Promise 数组数据 */
for (let i = 0; i < this.mainArray.length; i++) {
const resu = await this.getScrollTop(`#item-${i}`)
p_arr.push(resu - 200)
}
/* 主区域滚动容器的顶部距离 */
this.getScrollTop("#scroll-el").then((res) => {
let top = res;
// #ifdef H5
top += 43; //因固定提示块的需求,H5的默认标题栏是44px
// #endif
/* 所有节点信息返回后调用该方法 */
Promise.all(p_arr).then((data) => {
this.topArr = data;
});
})
},
/* 主区域滚动监听 */
mainScroll(e) {
if (!this.isMainScroll) {
return;
}
let top = e.detail.scrollTop;
let index = -1;
if (top >= this.topArr[this.topArr.length - 1]) {
index = this.topArr.length - 1;
} else {
index = this.topArr.findIndex((item, index) => {
return this.topArr[index + 1] >= top;
});
}
this.leftIndex = (index < 0 ? 0 : index);
// console.log('打印',this.leftIndex)
},
/* 主区域触摸 */
mainTouch() {
this.isMainScroll = true;
},
/* 左侧导航点击 */
leftTap(e) {
let index = e.currentTarget.dataset.index;
this.isMainScroll = false;
this.leftIndex = Number(index);
this.scrollInto = `item-${index}`;
}
}
}
</script>
<style lang="scss" scoped>
.content {
.head {
width: 100%;
height: 400rpx;
background-color: pink;
display: flex;
align-items: center;
justify-content: center;
}
.list_box {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: flex-start;
align-items: flex-start;
align-content: flex-start;
font-size: 28rpx;
height: calc(100vh - 400rpx);
.left {
width: 200rpx;
background-color: orange;
line-height: 80rpx;
box-sizing: border-box;
font-size: 32rpx;
height: 100%;
.item {
padding-left: 20rpx;
position: relative;
&:not(:first-child) {
margin-top: 1px;
&::after {
content: '';
display: block;
height: 0;
border-top: #d6d6d6 solid 1px;
width: 620upx;
position: absolute;
top: -1px;
right: 0;
transform: scaleY(0.5);
}
}
&.active,
&:active {
color: #42b983;
background-color: #fff;
}
}
}
.main {
height: 100%;
background-color: #fff;
padding: 0 20rpx;
width: 0;
flex-grow: 1;
box-sizing: border-box;
.tips {
line-height: 64rpx;
font-size: 24rpx;
font-weight: bold;
color: #666;
height: 64rpx;
position: fixed;
top: 44px;
right: 0;
width: 530rpx;
z-index: 10;
background-color: #fff;
padding-left: 10rpx;
}
.right-scroll {
height: calc(100vh - 400rpx);
width: 100%;
background-color: #efba21;
border-bottom: 2rpx solid #fff;
/* 横向滚动 */
white-space: nowrap;
flex-direction: row;
.item {
width: 100%;
height: 100%;
/* item的外层定义成行内元素才可进行滚动 inline-block / inline-flex 均可 */
display: inline-flex;
.goods {
width: 100%;
height: 100%;
padding: 20rpx;
box-sizing: border-box;
background-color: #42b983;
display: flex;
flex-direction: column;
flex-wrap: nowrap;
justify-content: center;
align-items: center;
align-content: center;
margin-bottom: 10rpx;
border-right: 2rpx solid #fff;
}
.goods:last-child {
border-right: 0;
}
}
}
.right-scroll:last-child {
border-bottom: 0;
}
}
.scroll {
height: 100%;
}
}
}
</style>
完成