前言:最近在做组内小程序全面升级改版、涉及到了一个交互的问题:左侧菜单随着右侧内容滚动选中、同时也可以点击左侧菜单进行选中。
在开发调研的过程中发现了几种实现的方案、特此记录一下、如果有小伙伴遇到相似的问题的话、希望给与你一些灵感哈
实现的效果如下:
实现方案:
1、scroll-view
scroll-view :可以通过小程序自带的组件进行交互、以scroll-into-view
为锚点进行点击左侧菜单进行定位 ,滚动的时候通过判断是在元素内相交还是在显示区进行相交,但是比较适合局部进行滚动的,
如下图这种布局:
如果头部有个banner图
的话, 如下图, 全局滚动就会有问题、需要监听滚动的是那个元素、比较麻烦,:
大致实现的效果如下:
2、onPageScroll + sticky
通过监听全局页面的滚动计算出 每个元素的scrollTop的距离,然后每次滚动进行右侧每个元素的scrolltop的计算是否在可视区即可。核心代码一览:
this.state = {
_active:1, //左侧选中的ID
navsContentDOM:[], // 获取的DOM元素
}
getDOM () {
clearTimeout(tdom)
tdom = setTimeout( async () => {
// 监听滚动的元素的scrollTop
const rtChildCard = () => {
return new Promise(function(resolve){
const query = Taro.createSelectorQuery()
query.selectAll('.index_rt_item').boundingClientRect((rect) => {
resolve(rect)
}).exec()
})
}
const _rtChildCard = await rtChildCard();
this.setState({
navsContentDOM:_rtChildCard
})
}, 200)
}
...
onPageScroll = debounce((obj) => {
const { navsContentDOM } = this.state; // 获取右侧的DOM节点
const top = obj.scrollTop;
if(navsContentDOM.length === 0) {
console.log('获取DOM节点失败')
return
}
for(let i = 0; i < navsContentDOM.length - 1; i++) {
if(top >= navsContentDOM[i].top && top < navsContentDOM[i + 1].top ) {
this.setState({
_active:+navsContentDOM[i].id
})
return
}
}
if(top >= navsContentDOM[navsContentDOM.length - 1].top ) {
this.setState({
_active:+navsContentDOM[navsContentDOM.length - 1].id
})
return
}
this.setState({
_active:+navsContentDOM[0].id
})
},100)
...
3、wx.createIntersectionObserver
wx.createIntersectionObserver可以创建并返回一个 IntersectionObserver 对象实例。通过指定的relativeToViewport
显示区域作为参照进行节点相交的监听当前视图内的节点是否相交、也可以用relativeTo
来指定区域的相交集合、这里就不进行演示了想深入了解的伙伴可以自行本地实验一下、尤其是createIntersectionObserver的thresholds
和initialRatio
最后:
不同的场景、需要考虑不同的解决方案、希望以上的内容对大家有所帮助。