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

这几天整索引列表,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
			}
		},

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
可以参考以下代码: ```html <template> <view> <scroll-view class="scroll-view" scroll-x="true"> <view class="tab-item" :class="{active: activeIndex === index}" v-for="(item, index) in tabs" :key="index" @tap="handleTabClick(index)">{{item}}</view> </scroll-view> <view class="list-wrap"> <view class="list" v-show="activeIndex === 0"> <view v-for="(item, index) in list1" :key="index">{{item}}</view> </view> <view class="list" v-show="activeIndex === 1"> <view v-for="(item, index) in list2" :key="index">{{item}}</view> </view> <view class="list" v-show="activeIndex === 2"> <view v-for="(item, index) in list3" :key="index">{{item}}</view> </view> </view> </view> </template> <script> export default { data() { return { tabs: ['列表1', '列表2', '列表3'], activeIndex: 0, list1: ['列表1-1', '列表1-2', '列表1-3'], list2: ['列表2-1', '列表2-2', '列表2-3'], list3: ['列表3-1', '列表3-2', '列表3-3'] } }, methods: { handleTabClick(index) { this.activeIndex = index } } } </script> <style> .scroll-view { display: flex; white-space: nowrap; } .tab-item { padding: 20rpx 30rpx; font-size: 32rpx; color: #999; } .tab-item.active { color: #333; border-bottom: 4rpx solid #333; } .list-wrap { height: calc(100vh - 200rpx); overflow: auto; } .list { padding: 20rpx; font-size: 28rpx; line-height: 1.5; color: #333; } </style> ``` 其中,我们使用了一个 `scroll-view` 实现了多个横向滚动的标签,并用 `v-for` 渲染了多个列表,通过 `v-show` 根据 `activeIndex` 的值来显示或隐藏对应的列表。最后,我们使用了 `@tap` 监听标签的点击事件,并将 `activeIndex` 的值更新为点击的标签的索引,从而实现了多列表切换。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值