uni-app 高性能的左右长列表,tab列表

前言:笔者一名业余的码农,只是爱好而已。刚从html转到uni-app这边,vue也是第一次写。
效果:
在这里插入图片描述

像这个可以左右切换的长列表,上面的tab倒是很好实现,直接使用官方的scroll-view组件就可以了。
但是下方的长列表,要实现并且保证高性能,可不是一件容易事。

下方内容列表一开始,我是考虑使用swiper组件的,但是swiper组件的高度始终是固定的,即便你动态修改了。但依旧是固定的高度,以后内容变化的话,都得重新获取高度。所以排除掉

scroll-view组件的话,官方文档早就说明不适合做长列表了。
看来就剩下插件市场的list组件了,但是我没用过,但是我可以预见的是,list组件,扩展性低,复杂(相较于我这种第一次写vue的),性能也就那样,至少在HTML端的性能是不会很好的

所以就自己写一个,原理就是直接使用view,父view设置css属性为display: inline-flex;。大致如下图
在这里插入图片描述
然后切换使用css平移动画 transform:translateX(0); 性能非常的好。缺点就是要实现手势左右滑动进行切换得自己写js,不过也不难。

另外上面的tab。那条橙色的线,位置和宽度是会变化的,一开始使用的是left 和 width,来实现。然后发现在列表内容很多的情况下,性能很差,所以就改成了css的平移和缩放动画,来实现偏移和宽度变化(性能很好)。
上面tab被点击之后也会居中显示

下面是具体代码

根目录中创建components文件夹(components是自定义组件的存放地),components文件夹中创建list.vue文件,文件内容如下

<template><view>
<view style="background:#FFFFFF;">
	<scroll-view class="navList" scroll-x="true" scroll-with-animation="true" :scroll-left="setNavScrollLeft">
		<text class="text" v-for="(item, index) in nav" :class="{'active':navListIndex === index}" @click="navClick(index)">
			<text class="span">{{item}}</text>
			<text v-if="index === 0" class="line" :style="{'transform':lineTransform,'transition-duration':line_transitionDuration}"></text>
		</text>
	</scroll-view>
</view>

<view class="content" :style="{'transform':contentTransform}">
	<view v-for="(item, index) in nav" :key="index" class="goodsList">
		<view class="li">
			<image class="zutu" src="//img.alicdn.com/bao/uploaded/i2/3339093752/O1CN01zDfREI1daShv15vyU_!!0-item_pic.jpg" mode="scaleToFill"></image>
			{{index}}1
		</view>
		<view class="li">
			<image class="zutu" src="//img.alicdn.com/bao/uploaded/i2/3339093752/O1CN01zDfREI1daShv15vyU_!!0-item_pic.jpg" mode=""></image>
			{{index}}2
		</view>
		<view class="li"><image class="zutu" src="//img.alicdn.com/bao/uploaded/i2/3339093752/O1CN01zDfREI1daShv15vyU_!!0-item_pic.jpg" mode=""></image>3</view>
		<view class="li"><image class="zutu" src="//img.alicdn.com/bao/uploaded/i2/3339093752/O1CN01zDfREI1daShv15vyU_!!0-item_pic.jpg" mode=""></image>4</view>
		<view class="li"><image class="zutu" src="//img.alicdn.com/bao/uploaded/i2/3339093752/O1CN01zDfREI1daShv15vyU_!!0-item_pic.jpg" mode=""></image>5</view>
		<view class="li"><image class="zutu" src="//img.alicdn.com/bao/uploaded/i2/3339093752/O1CN01zDfREI1daShv15vyU_!!0-item_pic.jpg" mode=""></image>6</view>
		<view class="li"><image class="zutu" src="//img.alicdn.com/bao/uploaded/i2/3339093752/O1CN01zDfREI1daShv15vyU_!!0-item_pic.jpg" mode=""></image>7</view>
		<view class="li"><image class="zutu" src="//img.alicdn.com/bao/uploaded/i2/3339093752/O1CN01zDfREI1daShv15vyU_!!0-item_pic.jpg" mode=""></image>8</view>
		<view class="li"><image class="zutu" src="//img.alicdn.com/bao/uploaded/i2/3339093752/O1CN01zDfREI1daShv15vyU_!!0-item_pic.jpg" mode=""></image>9</view>
		<view class="li"><image class="zutu" src="//img.alicdn.com/bao/uploaded/i2/3339093752/O1CN01zDfREI1daShv15vyU_!!0-item_pic.jpg" mode=""></image>10</view>
		<view class="li"><image class="zutu" src="//img.alicdn.com/bao/uploaded/i2/3339093752/O1CN01zDfREI1daShv15vyU_!!0-item_pic.jpg" mode=""></image>11</view>
		<view class="li"><image class="zutu" src="//img.alicdn.com/bao/uploaded/i2/3339093752/O1CN01zDfREI1daShv15vyU_!!0-item_pic.jpg" mode=""></image>12</view>
		<view class="li"><image class="zutu" src="//img.alicdn.com/bao/uploaded/i2/3339093752/O1CN01zDfREI1daShv15vyU_!!0-item_pic.jpg" mode=""></image>13</view>
		<view class="li"><image class="zutu" src="//img.alicdn.com/bao/uploaded/i2/3339093752/O1CN01zDfREI1daShv15vyU_!!0-item_pic.jpg" mode=""></image>14</view>
		<view class="li"><image class="zutu" src="//img.alicdn.com/bao/uploaded/i2/3339093752/O1CN01zDfREI1daShv15vyU_!!0-item_pic.jpg" mode=""></image>15</view>
	</view>
</view>
</view></template>
<script>
	export default {
		props:{
			nav:{type:Array,default:[]},
		},
		data() {
			return {
				lineTransform:'',//线条
				setNavScrollLeft:0,//初始化的位置,可以动态调节
				navListIndex:0,//默认第几个
				line_transitionDuration:'0ms',//过渡时间
				navWidth:0,//滚动条视口的宽度
				
				contentTransform:'translateX(0)',//当前所在滑块的 index
			};
		},
		mounted(){//该组件被挂载到实例上去之后调用
			//初始化 线 显示的位置	transition-duration: 400ms;
				uni.createSelectorQuery().in(this).select(".navList .text.active .span").boundingClientRect((data) => {
					this.lineTransform = 'translateX('+(data.left+(data.width-19)/2)+'px) scaleX('+(data.width/20)+')';
					//偏移值=第一个分类相对于视口的水平位置+(第一个分类的宽度-19)/2		除以2的原因是后面的缩放是沿着左右两边进行缩放的,所以除以2可以让其居中
					//减19是因为默认宽度就是20,需要减到1px之后才进行结算,那么问题就来了,为什么不在直接使用1px呢?因为使用1px,需要缩放很多倍,在移动端,进行多倍的缩放之后,宽度是不对的,所以设置20px,就不需要进行很多倍的缩放,没有css兼容问题
					setTimeout(() => {
						this.line_transitionDuration = '400ms';
					}, 50);
				}).exec();
			//nav的可视宽度【不包含margin】
				uni.createSelectorQuery().in(this).select(".navList").boundingClientRect((data) => {
					this.navWidth = data.width;
				}).exec();
		},
		methods: {
			navClick(index){
				this.navListIndex = index;
				this.contentTransform = 'translateX(-'+index+'00vw)';
				let left = 0,
					avtiveNavWidth = 0;//当前nav中被选择的分类的宽度
				//滚动条已滚动的水平长度
					uni.createSelectorQuery().in(this).select(".navList").scrollOffset((data) => {
						left = data.scrollLeft;
					}).exec();
				//偏移(元素的相对于视口的定位 + 滚动条横向的位置) and 缩放(实现宽度变化)
					uni.createSelectorQuery().in(this).select(".navList .text:nth-of-type("+(index+1)+") .span").boundingClientRect((data) => {
						left += data.left;
						this.lineTransform = 'translateX('+(left+(data.width-19)/2)+'px) scaleX('+(data.width/20)+')';
						left -= (data.width/2);
						avtiveNavWidth = data.width;
					}).exec();
				//居中
				//计算nav的margin-left,27是他的“27rpx”【【居中时,要减去这部分】】
					uni.getSystemInfo({
						success: (res) => {
							this.setNavScrollLeft = left - Math.round(res.windowWidth*(27/750)) - (this.navWidth / 2) + avtiveNavWidth;
						}
					});
			},
		},
	}
</script>
<style>
	.content{
		display: inline-flex;
		transition-duration:500ms;
	}
	.goodsList{
		width: 750rpx;
		box-sizing:border-box;
		padding: 20rpx;
	}
	.goodsList .li{
		display:inline-block;
		background:#FFF;
		width:347rpx;
		margin-bottom: 15rpx;
		border-radius:14rpx;
		overflow:hidden;
	}
	.goodsList .li:nth-child(even){
		margin-left: 20rpx;
	}
	.goodsList .li .zutu{
		width:100%;
		height:347rpx;
	}
	
	
	.navList{
		Position:relative;
		background:#FFFFFF;
		font-size: 28rpx;
		width:696rpx;
		margin:0 27rpx;
		box-shadow: inset -31rpx 0 31rpx -31rpx rgba(0,0,0,0.15);
		line-height:66rpx;
		white-space: nowrap;
	}
	.navList .text{
		padding-left:30rpx;
		color: #333;
	}
	.navList .text:nth-of-type(1){
		padding-left:0;
	}
	.navList .text:nth-last-child(1){
	    padding-right: 19rpx;
	}
	.navList .text.active{
		color:#FF5500;
	}
	.navList .line{
		background: #ff5500;
		Position: absolute;
		left: -27rpx;
		bottom: 4rpx;
		width:20px;
		height: 4rpx;
	}
</style>

然后在你需要的地方引入这个文件

<script>
import list from '@/components/list.vue'
export default {
	components:{//注册组件
		list
	},
    data() {
        return {
			nav:['精选','女装','家居数码','数码家电数码家电','食品','母婴','鞋包配饰','美妆个护','男装','内衣','运动个护','淘宝','京东'],
        }
    },
}
</script>

调用组件

<list :nav="nav"></list>

性能没问题,在13个分类列表里面,每个列表中创建93个商品,切换过程没有一点点卡顿

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
uni-app是一种基于Vue.js框架开发的跨平台应用开发框架,可以用来快速开发iOS、Android和Web应用。在处理列表时,为了提高性能和用户体验,可以采取以下优化措施。 1. 使用虚拟列表:传统的列表采用一次性渲染所有数据的方式,当数据较多时,会导致页面渲染时间过。虚拟列表是一种只渲染可见区域数据的方式,当用户滚动列表时,动态加载新的数据。这样可以极大地减少页面渲染时间,并且提高滚动的流畅性。 2. 优化数据渲染方式:在数据量较大的情况下,通过简化数据模型、避免嵌套循环等方式,可以减少渲染时的计算量,从而提高渲染性能。同时,可以使用v-for指令中的key属性来跟踪列表项的变化,减少不必要的重渲染。 3. 列表项复用:当列表项较多时,为了提高内存利用率和性能,可以采用复用机制。即在滚动时,将滚出可见区域的列表项回收到一个对象池中,然后将新进入可见区域的列表项从对象池中取出复用。这样可以避免频繁地创建和销毁列表项,改善性能。 4. 异步加载数据:对于数据量较大的列表,可以采用异步加载数据的方式。在初始渲染时,只加载当前可见区域的数据,滚动列表时再异步加载新的数据。这样可以减少初始渲染时间,并且提高用户体验。 5. 页面性能优化:除了针对列表进行优化外,还可以从整体页面性能方面入手,如减少不必要的组件渲染、使用合适的图片压缩方式、图标字体代替图片等,以提高整体应用的性能。 总的来说,uni-app列表的性能优化可从虚拟列表、数据渲染方式、列表项复用、异步加载数据和页面性能等多个方面入手。通过合理的优化措施,可以提高列表的渲染性能,提升用户体验。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值