uniapp列表左右联动功能的实现:
电商类、外卖类web或者小程序常用,左侧点击对应的tag,右侧会滚动到对应的内容上;右侧滚动,左侧也会到指定位置高亮。
前言
容易出错的是,在获取元素时,需要在DOM加载完毕后获取,这里会涉及到生命周期的知识。
实现
这里对css样式不做过多赘述,css我会放在下面,有兴趣的朋友可以自行查看,只针对功能实现。
1.点击高亮
首先左右联动的实现是基于点击高亮,列表滚动,这两个基础功能来实现的。所以我在获取了后端传来的数据后,使用active和index去确定我具体点击了哪个位置,就让哪个位置高亮,代码如下:
<scroll-view scroll-y="true" :style="{ 'height':scrollHeight + 'px' }" :scroll-with-animation="false"> <view class="item" v-for="(item,index) in cateData" :key="index" :class="{ 'active':index === leftIndex }" :id="'left-'+index" @tap="leftTap(index)"> {{item.name}} </view> </scroll-view> /* 左侧导航点击 */ leftTap(e){ this.leftIndex = e this.$emit('getInto', "item-" + e) }
左边列表的高度,我使用了动态高度,这是由父组件获取其他元素高度后计算得出的,得到高度后使用组件传值方式,再传递回来。也是方便后续如果页面发生了改变,新增了其他组件进而对高度进行调整。
class:当我触发了点击事件后,我将获取到点击的具体某一项元素的index重新赋值,然后给出判断
:class="{ 'active':index === leftIndex }"
这个条件成立,我就调用名为active的样式。而后面的this.$emit是将点击后的index拼接传到父组件中,因为在右侧列表的位置判断上我需要用到。
2.右侧列表滚动
滚动我使用了原生的scroll-view,代码如下:
<scroll-view scroll-y="true" :style="{ 'height':scrollHeight + 'px' }" :scroll-into-view="scrollInto" :scroll-with-animation="false" @scroll="mainScroll"> <view class="item main-item" v-for="(item,index) in cateName" :key="index" :id="'item-'+index" @tap="click"> <view class="title"> <view>{{item.cateName}}</view> </view> <view class="goods" v-if="item.cateId === item2.cateId" v-for="(item2,index2) in listData" :key="index2"> <image :src="item2.logo" mode=""></image> <view> <view>{{item2.name}}</view> <view class="describe">{{item2.subname}}</view> </view> </view> </view> <view class="fill-last" :style="{ 'height':fillHeight + 'px' }"></view> </scroll-view>
这里比较关键的地方就是:scroll-into-view="scrollInto",通过文档可知:
是用来控制,滚动区域具体显示某个子元素的。如果我在左侧点击的时候就能知道我要显示的右侧列表的中的某一项的子元素id的话,是不是就能实现,点击后,右侧显示具体的内容了呢?
答案是肯定的。
上面我们说到了,将事件使用$emit抛出,那么在父组件中就能够获取到,
<!-- 滚动区域 --> <tool-wap-left-list ref="ToolWapLeftList" :scrollHeight="scrollHeight" @getInto="getval"> </tool-wap-left-list> <tool-wap-content-list ref="ToolWapContentList" :scrollHeight="scrollHeight" :scrollTopSize="scrollTopSize" @getIndex="getIndex"> </tool-wap-content-list> getval(val) { this.$refs.ToolWapContentList.scrollInto = val }
这里我们就能够通过改变scrollInto进而控制右侧滚动的位置了。
当然,我们首先要先获取到右侧滚动区域的所有元素和它们的顶部高度才行。
/* 获取元素顶部信息 */ getElementTop() { console.log('this.scrollHeight', this.scrollHeight); new Promise((resolve, reject) => { let view = uni.createSelectorQuery().selectAll('.main-item'); view.boundingClientRect(data => { resolve(data); }).exec(); }).then((res) => { let topArr = res.map((item) => { return item.top - this.scrollTopSize; /* 减去滚动容器距离顶部的距离 */ }); this.topArr = topArr; /* 获取最后一项的高度,设置填充高度。判断和填充时做了 +-20 的操作,是为了滚动时更好的定位 */ let last = res[res.length - 1].height; if (last - 20 < this.scrollHeight) { this.fillHeight = this.scrollHeight - last + 20; } }); },
这里对滚动到最后元素时,不满页面做了一个填充。
同理,左侧的高亮我们也可以通过该逻辑实现。
/* 主区域滚动监听 */ mainScroll(e) { // 节流方法 clearTimeout(this.mainThrottle); this.mainThrottle = setTimeout(() => { scrollFn(); }, 10); let scrollFn = () => { let top = e.detail.scrollTop; let index = 0; /* 查找当前滚动距离 */ for (let i = (this.topArr.length - 1); i >= 0; i--) { /* 在部分安卓设备上,因手机逻辑分辨率与rpx单位计算不是整数,滚动距离与有误差,增加2px来完善该问题 */ if ((top + 2) >= this.topArr[i]) { index = i; break; } } this.leftIndex = (index < 0 ? 0 : index); this.$emit('getIndex', this.leftIndex) } },
以上就是左右联动的实现方法了。