赞
踩
H5端tab切换及tab锚点效果
小程序端tab切换及tab锚点效果
//topicList后端返回的数据
<view :id="'a' + (i + 1)" v-for="(v,i) in topicList" :key="v.id">
<template> <u-tabs :list="tabList" :current="currentTab" @change="changeTab" :bar-style="{'bottom':'6rpx'}"></u-tabs> </template> // 根据后端返回数据总条数计算tab getTopicTab() { // this.topicList.length这是渲染数据总条数,20是每个tab数值间隔值,cycleIndex则是针对数据总条数一共有几个tab let cycleIndex = Math.ceil(this.topicList.length / 20); // 向上取整6.01 -> 7 let tabArr = []; for(let i = 1; i <= cycleIndex; i++) { tabArr.push({ value: 20 * i, name: ((20 * (i - 1)) + 1) + '-' + (i == cycleIndex ? this.topicList.length : (20 * i)), id: '#a' + ((20 * (i - 1)) + 1) }); }; this.tabList = tabArr; },
export default { data() { tabList: [], // 切题tab集合 topicList: [], // 题库集合 distanceArr: [], // 每道题ID对应的top值 isTabChange: false, // 防止在点击tab的时候,页面的滚动导致重复计算、抖动问题 }, // 监听页面滚动 onPageScroll (event) { if (this.isTabChange) { return }; const { scrollTop } = event; // 偏移量,由于吸顶的tab、头部的显示信息也有高度,素以做了偏移量 // (这里是代码实现第5点及实现思路第4点提到的偏移量) const skewY = 103; if (scrollTop >= skewY) { this.$nextTick(() => { // distanceArr-进入页面时第一时间获取每个tab对应item的top值集合 const length = this.distanceArr.length; const index = this.distanceArr.findIndex(el => el - skewY - scrollTop > skewY); // 当index == -1 的时候,实际当前滚动的距离超出了最大值,也就是在最后一个tab显示的内容 // 当index > 0 的时候,说明能在当前的scrollTop值找到,即index的前一位 // currentTab 0激活第一个切题tab 1第二个 this.currentTab = index > 0 ? index - 1 : length - 1; }) } }, methods: { // 获取题库 getList() { this.topicList = [] }, // 根据this.topicList计算切题tab getTopicTab() { let cycleIndex = Math.ceil(this.topicList.length / 20); // 向上取整6.01 -> 7 let tabArr = []; for(let i = 1; i <= cycleIndex; i++) { tabArr.push({ value: 20 * i, name: ((20 * (i - 1)) + 1) + '-' + (i == cycleIndex ? this.topicList.length : (20 * i)), id: '#a' + ((20 * (i - 1)) + 1) }); }; this.tabList = tabArr; }, // 获取每个tab对应item的top值集合('20-41'获取第21个item的top值) getDistanceArr () { const _this = this; _this.$nextTick(() => { const query = uni.createSelectorQuery().in(_this); _this.tabList.map(el => { query.select(el.id).boundingClientRect(data => { // 获取当前ID距离顶部的top值 if(!_this.distanceArr.includes(data.top)) { _this.distanceArr.push(data.top) } }).exec() }) }); }, // 切题tab changeTab(index) { // 防止在点击tab的时候,页面的滚动导致重复计算、抖动问题 // true时监听页面滚动生命周期代码则不执行 this.isTabChange = true; this.currentTab = index; const _this = this; // this.$nextTick 保证当前isTabChange 为true后执行代码 // 避免在istabChange变为true的时候,执行代码,监听事件还是会继续执行重新计算currenTab值 _this.$nextTick(() => { const query = uni.createSelectorQuery().in(_this); let id = _this.tabList[index].id; let dataTop; query.select(id).boundingClientRect(data => { dataTop = data.top; }).exec(); query.select('.page-risk').boundingClientRect(res => { const scrollTop = dataTop - res.top // 获取差值 const skewY = 103 // 偏移(顶部返回和切换题tab的高度及第一题magin/padding的和) // 页面开始进行滚动到目标位置 uni.pageScrollTo({ scrollTop: scrollTop > 0 ? scrollTop - skewY : scrollTop + skewY, duration: 300, complete: function () { const timer = setTimeout(() => { _this.isTabChange = false // 关闭(放开对onPageScroll的限制) clearTimeout(timer) }, 500) // 解决ios和安卓、鸿蒙系统兼容性问题 } }); }).exec() }) }, // 这里业务是题库,所以当必填项没有填写时,就会锚点到该位置 // 前提是需要将必填项且没有填写的item的id值传递过来 getPageScrollTo(id) { const _this = this; _this.$nextTick(() => { const query = uni.createSelectorQuery().in(_this); let index = '#a' + (id + 1); let dataTop; query.select(index).boundingClientRect(data => { dataTop = data.top; }).exec(); query.select('.page-risk').boundingClientRect(res => { const scrollTop = dataTop - res.top; // 获取差值 const skewY = 103; // 偏移 // 页面开始进行滚动到目标位置 uni.pageScrollTo({ scrollTop: scrollTop > 0 ? scrollTop - skewY : scrollTop + skewY, duration: 300, }); }).exec() }) }, } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。