uni-app 高性能的左右长列表,tab列表
前言:笔者一名业余的码农,只是爱好而已。刚从html转到uni-app这边,vue也是第一次写。效果:像这个可以左右切换的长列表,上面的tab倒是很好实现,直接使用官方的scroll-view组件就可以了。但是下方的长列表,要实现并且保证高性能,可不是一件容易事。下方内容列表一开始,我是考虑使用swiper组件的,但是swiper组件的高度始终是固定的,即便你动态修改了。但依旧是固定的高度,以后内
前言:笔者一名业余的码农,只是爱好而已。刚从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个商品,切换过程没有一点点卡顿
更多推荐
所有评论(0)