uni-app scroll-view + tab锚点定位

uni-app滚动定位与tab逻辑实现详解

逻辑梳理:在实现相应交互时对整个过程做一下分析

1:如何计算tab对应view滚动的距离?

根据大家需要实现的UI效果对应调整

return new Promise(resolve => {
	if(index == 0) {
		resolve(0);
		return;
	}
	uni.createSelectorQuery().in(this).select(`#view${index}`).boundingClientRect(
	data => { //目标位置节点 类或者 id
		uni.createSelectorQuery().in(this).select(".scroll-view").boundingClientRect((
			res) => { //最外层盒子节点类或者 id
				let scrollViewTop = (data.top - res.top);
				resolve(scrollViewTop);
			}).exec()
	}).exec();
});

2:如何滑动至指定位置?

  1. 页面层的滚动:
    uni.pageScrollTo({ scrollTop: 0, duration: 100, });
  2. scroll-view层的滚动:
    :scroll-top="number" 设置对应属性值来实现
    :scroll-into-view="id-view" 设置对应属性值来实现

3:滑动时如何判断tab当前索引?

获取当前滚动位置,与tab对应的view滚动区间做对比:

  1. 获取当前滚动位置scrollTop(number)
    页面层的滚动:
    使用生命周期onPageScroll()进行监听
    scroll-view层的滚动:
    通过事件@scroll 进行监听
    -以此获取当前滚动位置
  2. tab对应的view滚动区间scrollViewTopData(array):
    通过上面第一点计算,我们已经拿到
    满足 (scrollTop < (scrollViewTopData[i + 1]) ||
    (i + 1 == scrollViewTopData.length && scrollViewTopData[i] <= scrollTop)
    设置 currentTabIndex = i;

4:切换tab时注意事项以及优化?

  1. 滚动监听优化,合理节流例如:1滚动监听加延时,2切换tab时加标识阻止滚动监听;
  2. 确保页面渲染成功;
  3. 滚动时,计算不准确,可能为负数;
  4. 页面数据变化时,记得重新计算,以免滚动位置不准确;
### 实现 uni-appscroll-view 组件的无缝循环滚动 为了实现在 `uni-app` 的 `scroll-view` 组件中的无缝循环滚动效果,可以采用设置定时器来自动触发滚动位置的变化,并通过监听滚动事件调整显示的内容。需要注意的是,在实现过程中应避免使用带有 `fixed` 属性的元素以防止视图随页面滚动而移动[^1]。 下面是一个简单的例子展示如何创建一个水平方向上的无限轮播: ```html <template> <view class="container"> <!-- 设置横向滚动 --> <scroll-view class="scroll-view_H" :scroll-x="true" @scroll="handleScroll" :scroll-left="scrollLeft" ref="scrollViewRef" > <block v-for="(item, index) in items.concat(items)" :key="index"> <view class="scroll-item">{{ item }}</view> </block> </scroll-view> </view> </template> <script> export default { data() { return { items: ['Item 1', 'Item 2', 'Item 3'], // 原始数据项 currentIndex: 0, timer: null, scrollLeft: 0 }; }, mounted() { this.startAutoScroll(); }, methods: { handleScroll(e) { const { detail } = e; let width = Math.round(detail.scrollWidth / (this.items.length * 2)); if ((detail.scrollLeft >= width && !this.isAnimating)) { this.currentIndex++; this.scrollToNext(); } }, scrollToNext() { this.$nextTick(() => { this.scrollLeft += this.$refs.scrollViewRef.offsetWidth; // 更新滚动距离 setTimeout(() => { this.resetPosition(); // 调整回初始状态 }, 50); }); }, resetPosition() { this.scrollLeft -= this.$refs.scrollViewRef.offsetWidth; this.currentIndex %= this.items.length; if (this.timer !== null) clearTimeout(this.timer); this.startAutoScroll(); }, startAutoScroll() { this.timer = setInterval(() => { this.scrollToNext(); }, 3000); // 自动切换时间间隔 } }, beforeDestroy() { clearInterval(this.timer); } }; </script> <style scoped> .container { position: relative; } .scroll-view_H { white-space: nowrap; overflow: hidden; height: 80px; } .scroll-item { display: inline-block; min-width: 100%; text-align: center; line-height: 80px; font-size: 36rpx; } </style> ``` 此代码片段展示了如何利用 Vue.js 和 CSS 来构建一个基本的水平无限轮播功能。这里的关键在于将原始列表重复一次并连接起来形成一个新的数组用于渲染,这样当到达最后一个项目时就可以平滑过渡到第一个项目上从而达到视觉上的连续性。同时设置了定时器每隔一段时间调用方法使容器向右滚动一定宽度的距离模拟自动播放的效果;并且在每次完成一轮完整的动画之后重置当前位置以便继续下一个周期的播放。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值