微信小程序实现导航选中功能

527 阅读2分钟

前言:最近在做组内小程序全面升级改版、涉及到了一个交互的问题:左侧菜单随着右侧内容滚动选中、同时也可以点击左侧菜单进行选中。
在开发调研的过程中发现了几种实现的方案、特此记录一下、如果有小伙伴遇到相似的问题的话、希望给与你一些灵感哈

实现的效果如下:

demo.gif

实现方案:

1、scroll-view

scroll-view :可以通过小程序自带的组件进行交互、以scroll-into-view 为锚点进行点击左侧菜单进行定位 ,滚动的时候通过判断是在元素内相交还是在显示区进行相交,但是比较适合局部进行滚动的,

如下图这种布局:

image.png

如果头部有个banner图的话, 如下图, 全局滚动就会有问题、需要监听滚动的是那个元素、比较麻烦,:

image.png

大致实现的效果如下:

demo1.gif

点击查看具体的代码实现

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的thresholdsinitialRatio

最后:

不同的场景、需要考虑不同的解决方案、希望以上的内容对大家有所帮助。