uniapp插件索引列表uv-index-list增加返回头部的按钮

博主在uni-app开发中,因原生索引列表不满足需求,使用uv-index-list组件。但该组件无返回顶部功能,博主通过修改组件vue文件,处理索引偏移、添加返回顶部箭头对应id等操作,实现点击索引跳转,还解决了uv-index-item初始化导致的跳转错位问题,此调整适用于H5环境。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这几天整索引列表,uniapp原生的索引列表太烂了,不太满足需求,所以找了个uv-index-list的索引列表来用,但是翻了翻组件示例发现没有返回顶部的功能,偏偏还得用到,就只能自己动手改了,这里记一下,说不定以后有类似的情况可以用上。

翻到uv-index-list的组件vue文件uv-index-list.vue,可以找到创建索引的view对应的class是uv-index-list__letter__item,照抄一份,去掉v-for的循环,里面的item换成向上箭头↑

<view
			class="uv-index-list__letter"
			ref="uv-index-list__letter"
			:style="{ top: $uv.addUnit(letterInfo.top || 100 ,'px') }"
			@touchstart="touchStart"
			@touchmove.stop.prevent="touchMove"
			@touchend.stop.prevent="touchEnd"
			@touchcancel.stop.prevent="touchEnd"
		>
			<!-- 照抄一个创建索引的view -->
			<view
				class="uv-index-list__letter__item"
				:style="{
					backgroundColor: activeIndex === -1 ? activeColor : 'transparent'
				}"
			>
				<text
					class="uv-index-list__letter__item__index"
					:style="{color: activeIndex === -1 ? '#fff' : inactiveColor}"
				>↑</text>
			</view>
			<view
				class="uv-index-list__letter__item"
				v-for="(item, index) in uIndexList"
				:key="index"
				:style="{
					backgroundColor: activeIndex === index ? activeColor : 'transparent'
				}"
			>
				<text
					class="uv-index-list__letter__item__index"
					:style="{color: activeIndex === index ? '#fff' : inactiveColor}"
				>{{ item }}</text>
			</view>
		</view>

这里可以看到点击索引的时候会触发touchStart方法,顺着这个方法找,会看到touchStart的代码

// 索引列表被触摸
			touchStart(e) {
				// 获取触摸点信息
				const touchStart = e.changedTouches[0]
				if (!touchStart || this.disTap) return
				this.touching = true
				const {
					pageY
				} = touchStart
				// 根据当前触摸点的坐标,获取当前触摸的为第几个字母
				const currentIndex = this.getIndexListLetter(pageY)
				this.setValueForTouch(currentIndex)
			},

发现这里用getIndexListLetter获取了触摸点的坐标,然后用下面的setValueForTouch方法执行跳转事件,获取坐标的方法不用管,直接看到setValueForTouch,会看到里面是根据getIndexListLetter获取的触摸点对应的索引index执行了跳转,刚才已经在页面上增加了一个↑的索引了,所以这里要减去↑的偏移量,并且设置↑对应滚动的id:uv-index-item-header

// 设置各项由触摸而导致变化的值
			setValueForTouch(currentIndex) {
				// 如果是0的情况表示是向上箭头,直接回到顶部
				if(currentIndex == 0){
					// 设置当前激活的是表头
					this.activeIndex = -1;
					// 根据id返回到表头所在的位置
					this.scrollIntoView = 'uv-index-item-header'
					return
				}
				// 如果偏移量太小,前后得出的会是同一个索引字母,为了防抖,进行返回
				if (currentIndex - 1 === this.activeIndex) return
				// 偏移量减去返回顶部箭头
				this.activeIndex = currentIndex - 1
				// #ifndef APP-NVUE || MP-WEIXIN
				// 在非nvue中,由于anchor和item都在uv-index-item中,所以需要对index-item进行偏移
				this.scrollIntoView = `uv-index-item-${this.uIndexList[this.activeIndex].charCodeAt(0)}`
				// #endif
				// #ifdef MP-WEIXIN
				// 微信小程序下,scroll-view的scroll-into-view属性无法对slot中的内容的id生效,只能通过设置scrollTop的形式去移动滚动条
				this.scrollTop = this.children[this.activeIndex].top
				// #endif
				// #ifdef APP-NVUE
				// 在nvue中,由于cell和header为同级元素,所以实际是需要对header(anchor)进行偏移
				const anchor = `uv-index-anchor-${this.uIndexList[this.activeIndex]}`
				dom.scrollToElement(this.anchors[this.activeIndex].$refs[anchor], {
					offset: 0,
					animated: false
				})
				// #endif
			},

设置到这里的时候,调试会发现点索引会产生偏移,这是因为初始化组件的时候没有把↑的位置考虑上,翻到mounted钩子,看到用到了setIndexListLetterInfo设置索引和坐标的关系,所以这里加上↑的高度来处理

// 设置indexList索引的尺寸信息
			setIndexListLetterInfo() {
				this.getIndexListLetterRect().then(size => {
					const {
						top,
						height
					} = size
					const windowHeight = this.$uv.sys().windowHeight;
					let customNavHeight = 0
					// 消除各端导航栏非原生和原生导致的差异,让索引列表字母对屏幕垂直居中
					if (this.customNavHeight == 0) {
						// #ifdef H5
						customNavHeight = this.$uv.sys().windowTop
						// #endif
						// #ifndef H5
						// 在非H5中,为原生导航栏,其高度不算在windowHeight内,这里设置为负值,后面相加时变成减去其高度的一半
						customNavHeight = 0
						// #endif
					} else {
						customNavHeight = this.$uv.getPx(this.customNavHeight)
					}
					this.letterInfo = {
						height,
						// 为了让字母列表对屏幕绝对居中,让其对导航栏进行修正,也即往上偏移导航栏的一半高度
						top: (windowHeight - height) / 2 + customNavHeight / 2,
						// 初始化itemHeight的时候加上返回表头符号的高度
						itemHeight: Math.floor(height / (this.uIndexList.length + 1))
					}
				})
			},

到这个时候,基本点击其他索引都没啥问题了,但是点击返回顶部的箭头没有反应,这里就用上了刚才加的↑元素对应的id:uv-index-item-header,把id给插槽header加上

<scroll-view
			:scrollTop="scrollTop"
			:scrollIntoView="scrollIntoView"
			:offset-accuracy="1"
			:style="{
				maxHeight: $uv.addUnit(scrollViewHeight,'px')
			}"
			scroll-y
			@scroll="scrollHandler"
			ref="uvList"
		>
			<!-- header的view加上跳转对应的id -->
			<view id='uv-index-item-header'>
				<slot name="header" />
			</view>
			<slot />
			<view>
				<slot name="footer" />
			</view>
		</scroll-view>

到这里,基本跳转就都OK了,最后把点击索引显示的气泡加上

<uv-transition
			mode="fade"
			:show="touching"
			:customStyle="{
				position: 'fixed',
				right: '40px',
				top: $uv.addUnit(indicatorTop,'px'),
				zIndex: 2
			}"
		>
			<view class="uv-index-list__indicator__box">
				<view
					class="uv-index-list__indicator"
					:class="['uv-index-list__indicator--show']"
					:style="{
						height: $uv.addUnit(indicatorHeight,'px'),
						width: $uv.addUnit(indicatorHeight,'px')
					}"
				>
					<!-- activeIndex == -1 的情况表示返回表头 -->
					<text class="uv-index-list__indicator__text">{{ activeIndex == -1?'↑':uIndexList[activeIndex] }}</text>
				</view>
			</view>
		</uv-transition>

大功告成。

这里面其他用到的控制页面高度,索引栏的位置的其他方法,基本都不影响点击索引跳转,也就没必要修改了,另外这个调整只适用于uniapp的H5环境,且只适用于点击索引栏跳转,其他后续触发动作比如回传currentIndex的部分是没有改动的,这个请注意。

理论上这个插件是支持nvue和微信小程序的,不过我只用到H5的,调试也只调试H5的,所以不确定其他环境能不能使,大致也能当个参考。

补充一点内容

uv-index-item初始化的时候,class的名字会从A开始取charCodeAt,导致点击索引栏的时候跳转错位,去掉uv-index-item里面初始化调用init(),改为外部传入porps的charCode可以规避这个问题

<template>
	<!-- #ifdef APP-NVUE -->
	<cell ref="uv-index-item">
		<!-- #endif -->
		<view
			class="uv-index-item"
			:id="`uv-index-item-${charCode}`"
			:class="[`uv-index-item-${charCode}`]"
		>
			<slot />
		</view>
		<!-- #ifdef APP-NVUE -->
	</cell>
	<!-- #endif -->
</template>
props:{
			// 不使用原来的自动获取id的方式,会从A开始取charcode,导致id错位
			charCode:{
				type:Number,
				default:null
			}
		},

<think>好的,我现在需要帮助用户解决在UniApp中使用uView框架实现分类分页功能的问题,包括最后一页上拉切换到下一分类、下拉切换至上一分类,并加入橡皮筋效果。让我先理清用户的需求和可能的实现步骤。 首先,用户提到分类分页功能,需要上拉加载和下拉刷新,并且当到达最后一页时,上拉切换到下一个分类,下拉则切换到上一个分类。同时,还需要橡皮筋效果。这听起来像是结合了分页加载、分类切换以及手势操作的功能。 接下来,我需要回忆UniAppuView的相关知识。uView是一个UI框架,提供了丰富的组件和工具,可能已经封装了上拉加载和下拉刷新的组件,比如u-list或u-scroll-list。不过用户提到需要结合原生列表加载,可能涉及到使用uni-app的原生API,比如onReachBottom和onPullDownRefresh,或者使用uView的组件方法。 然后,分页功能通常涉及页码和每页数量的管理,当当前分类的数据加载完毕后,切换到下一个分类。这里需要维护当前分类的索引,比如currentCategoryIndex,当上拉加载时,检查当前分类是否还有更多数据,如果没有,就切换到下一个分类,并重置页码。同样,下拉刷新时,可能需要切换到上一个分类,但需要考虑边界情况,比如已经是第一个分类时如何处理。 橡皮筋效果通常指在滚动到顶部或底部时,有一定的弹性效果。这在uni-app中可能需要通过配置scroll-view组件的enhanced和bounce属性,或者在uView的组件中设置相关参数。例如,使用u-scroll-list组件时,设置bounce-top和bounce-bottom为true。 现在需要考虑如何结合这些元素。可能的步骤包括: 1. 使用uView的列表组件(如u-list)或uni-app的scroll-view来展示数据。 2. 监听上拉加载和下拉刷新事件,分别处理加载下一页和切换分类的逻辑。 3. 管理当前分类的索引和分页参数,确保正确加载数据。 4. 配置橡皮筋效果的相关属性,确保滚动时有弹性效果。 5. 处理数据加载时的状态,如显示加载中、没有更多数据等。 需要注意的问题包括: - 当切换分类时,如何重置分页参数(如页码从1开始)。 - 如何处理分类的循环,比如到达最后一个分类后是否回到第一个,或者停止切换。 - 下拉刷新时,如何切换到上一个分类,并在顶部显示刷新状态。 - 确保数据加载时,页面不会卡顿,使用异步加载数据。 - 处理边界情况,比如当前分类已经是第一个或最后一个时的反馈。 可能还需要参考用户提供的引用内容,特别是关于uni-app实现上拉加载和下拉刷新的方法。例如,引用[3]中提到了使用onReachBottom和onPullDownRefresh生命周期函数,以及停止刷新的方法uni.stopPullDownRefresh()。结合uView的组件,可能需要在这些生命周期函数中触发数据加载,并更新列表数据。 此外,用户提到的“橡皮筋效果”可能需要通过设置scroll-view的enhanced和bounce属性,或者在uView组件中启用相关配置。例如,在u-scroll-list中设置bounce属性为true。 接下来,我需要将这些思路整理成一个清晰的步骤,包括代码示例和配置说明。同时,需要确保LaTeX格式的正确应用,比如变量名用$...$包裹,独立公式用$$...$$,但在这个问题中可能涉及较少的数学公式,更多是代码和配置说明。 可能还需要考虑性能优化,比如避免重复请求,使用节流函数防止频繁触发加载事件,以及合理管理数据列表的状态,确保切换分类时数据正确更新。 最后,生成相关问题,帮助用户进一步了解相关主题,比如性能优化、其他分类切换方式、组件封装等。</think>### 实现UniApp中使用uView框架实现分类分页功能的步骤 #### 一、环境配置 1. 确保已安装`uview-ui`(v1.x版本),并在`main.js`中完成配置: ```javascript import uView from 'uview-ui' Vue.use(uView) ``` #### 二、核心逻辑实现 1. **数据结构定义**: ```javascript data() { return { currentCategoryIndex: 0, // 当前分类索引 categoryList: ['数码', '服饰', '食品'], // 分类数组 page: 1, // 当前页码 pageSize: 10, // 每页数量 dataList: [], // 当前分类数据 noMore: false, // 是否最后一页 loading: false // 加载状态 } } ``` 2. **分类切换与数据加载**: ```javascript // 切换分类时重置分页参数 async switchCategory(direction) { this.page = 1 this.currentCategoryIndex += direction // 边界处理(循环切换) if (this.currentCategoryIndex < 0) this.currentCategoryIndex = this.categoryList.length - 1 if (this.currentCategoryIndex >= this.categoryList.length) this.currentCategoryIndex = 0 await this.loadData() } // 加载数据(API调用示例) async loadData() { if (this.loading) return this.loading = true try { const res = await uni.request({ url: '/api/list', data: { category: this.categoryList[this.currentCategoryIndex], page: this.page, pageSize: this.pageSize } }) this.dataList = this.page === 1 ? res.data : [...this.dataList, ...res.data] this.noMore = res.data.length < this.pageSize this.page++ } finally { this.loading = false uni.stopPullDownRefresh() } } ``` 3. **事件绑定与生命周期**: ```javascript // 下拉刷新(切换上一分类) onPullDownRefresh() { this.switchCategory(-1) } // 上拉加载(触底判断) onReachBottom() { if (this.noMore) { this.switchCategory(1) // 切换到下一分类 } else { this.loadData() } } ``` #### 三、视图层实现(uView组件) ```html <template> <view class="container"> <!-- 分类标题 --> <u-navbar :title="categoryList[currentCategoryIndex]" :autoBack="false" /> <!-- 带橡皮筋效果的滚动区域 --> <u-scroll-list :bounce-top="true" :bounce-bottom="true" @scrolltolower="onReachBottom" > <!-- 数据列表 --> <view v-for="(item, index) in dataList" :key="index"> <u-cell :title="item.name" /> </view> <!-- 加载状态提示 --> <u-loadmore :status="noMore ? 'nomore' : 'loading'" :load-text="{ nomore: '没有更多了', loading: '正在加载...' }" /> </u-scroll-list> </view> </template> ``` #### 四、橡皮筋效果配置 1. 在`pages.json`中启用原生下拉刷新: ```json { "path": "pages/list/list", "style": { "enablePullDownRefresh": true, "onReachBottomDistance": 50 } } ``` 2. 通过CSS增强弹性效果: ```css /* 滚动容器样式 */ .u-scroll-list { height: 100vh; overflow: hidden; -webkit-overflow-scrolling: touch; /* 启用iOS弹性滚动 */ } ``` ### 关键实现说明 1. **分类切换机制**:通过`currentCategoryIndex`控制当前分类,当触底时判断是否切换分类(`noMore`为true时切换) 2. **数据加载优化**:使用`loading`状态防止重复请求,通过`page`参数实现分页逻辑 3. **边界处理**:分类索引超出范围时循环切换(可通过修改逻辑实现禁止循环) 4. **性能优化**: - 使用`u-scroll-list`虚拟列表处理大数据量 - 通过`-webkit-overflow-scrolling: touch`增强滚动流畅度[^3] ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值