手写小程序联动导航条组件

「这是我参与11月更文挑战的第9天,活动详情查看:2021最后一次更文挑战」。


前言

在业务需求中,导航条组件是一个非常常见的用户交互组件,市面上的一些比较主流的框架也都有对其进行封装。但是在一些比较小型的项目中,为了使用一个组件而引用一个框架未免有点杀鸡取卵,或是团队内部本就不允许使用第三方框架。这个时候就不得不自己手写一个组件。这里分享一下笔者在项目中自己写的导航条组件,提供的能力和拓展性虽然说没有市面上比较成熟的框架多,但是对于日常的业务场景也足够用了

准备工作

(这里默认读者对小程序开发有一定的了解) 在开始实现组件之前,我们先考虑一下这个组件我们需要提供什么能力。既然是导航条,那肯定要提供相应数据。其次就是点击回调事件。目前来看,好像透传这两个参数给组件便可以了。那么接下来我们就可以开始写组件了

组件设计

首先来看一下节点结构:

<view>
    <!-- scroll-left属性可以控制滚动条位置 -->
    <!-- scroll-with-animation滚动添加动画过渡 -->
    <scroll-view 
        scroll-x="true" 
        class="nav" 
        scroll-left="{{navScrollLeft}}" 
        scroll-with-animation="{{true}}" 
        style="background: {{background}}">
        <block wx:for="{{navData}}" wx:for-index="idx" wx:for-item="navItem" wx:key="idx">
            <view 
                class="nav-item {{[currentTab == idx ?'active':'', 'nav-item-' + idx]}} "  
                data-current="{{idx}}" 
                bindtap="switchNav" 
                style="color: {{currentTab == idx ? color : ''}}" >
                    {{navItem.text}}
            </view>
        </block>
    </scroll-view>
</view>
复制代码

这里我们可以看到,组件需要用的参数有 位移值(navScrollLeft)背景色(background)导航数据(navData)当前选中下标(currentTab)单项点击回调(switchNav)

从这五个参数分析,按照经验可以知道除了位移值和当前选中下标,其他均由外部传入。反之,位移值和当前选中下标即由组件自身定义,那么就来看看组件内对这些数据做了哪些处理

Component({
  properties: {
    navData: Array,
    cur: Number,
    color: {
      type: String,
      value: '#D60935',
    },
    background: {
      type: String,
      value: '#f7f7f7',
    }
  },
  data: {
    currentTab: 0,
    navScrollLeft: 0
  },
  attached: function () {
    wx.getSystemInfo({
      success: (res) => {
        this.setData({
          windowWidth: res.windowWidth
        })
      },
    })
  },
  methods: {
    switchNav(event) {  
      let that = this;
      let cur = event.currentTarget.dataset.current;
      const query = that.createSelectorQuery();
      query.select(`.nav-item-${cur}`).boundingClientRect();
      query.selectViewport().scrollOffset();
      query.exec(function(res){
        let offsetLeft = event.currentTarget.offsetLeft;
        that.setData({
          navScrollLeft: (offsetLeft - (that.data.windowWidth/2) + (res[0].width/2))
        });
      })

      if (that.data.currentTab == cur) {
        return false;
      } else {
        that.setData({
          currentTab: cur
        })
      }
      //向父组件传值
      that.triggerEvent('myevent',{cur: cur})
    }
  } 
})
复制代码

点击回调

我们在上文中提到过,点击回调事件应该由父级定义,这里看来好像是在组件内定义了。其实不然,这里只是在组件内注册了一个点击事件,因为位移计算这些总得让组件自身计算的,等组件内逻辑运算完,再调用一下父级的点击回调事件即可。

switchNav(event)函数 中我们可以看到,函数内最后执行了 that.triggerEvent('myevent',{cur: cur}) 即向父层发送事件通知,告知父层发生点击事件

位移值计算

说到位移值计算,这里我们得感谢小程序提供的 scroll-view 这个组件,这个组件的 scroll-left 属性,让我们用更少的代码可以实现平滑偏移效果:

  1. 组件内自身优化了偏移滑动效果
  2. scroll-left 的值超出元素最大宽度时,视图偏移量会向下取元素最大宽度

得益于 scroll-view 组件,我们只需要将关注点放在元素自身与视图间的位置关系即可,其中核心代码如下:

let cur = event.currentTarget.dataset.current;
const query = that.createSelectorQuery();
query.select(`.nav-item-${cur}`).boundingClientRect();
query.selectViewport().scrollOffset();
query.exec(function(res){
    let offsetLeft = event.currentTarget.offsetLeft;
    that.setData({
      navScrollLeft: (offsetLeft - (that.data.windowWidth/2) + (res[0].width/2))
    });
})
复制代码

当前选中下标

当前选中下标的处理相对比较简单,在点击的时候透传被点击的下标,即可获取当前选中下标了

let cur = event.currentTarget.dataset.current;
if (that.data.currentTab == cur) {
    return false;
} else {
    that.setData({
      currentTab: cur
    })
}
复制代码

但值得注意的是,由于我们可能需要指定初始化时的下标,所以将当前选中的下标值也由父级透传

如何使用

既然都已经封装好了,那我们只需要在需要用到组件的地方引入并声明组件即可使用了

<tabarNav 
    id="topNav" 
    bindmyevent="onMyEvent" 
    navData="{{navData}}" 
    cur="{{cur}}">
</tabarNav>
复制代码

具体入参的几个参数代表啥在这里也不做过多解释,想知道入参代表啥的同学自行翻阅 组件设计 章节。当然,在组件设计的时候,我们定义了不少参数,这里入参的仅有3个,其余参数可自行按需载入

猜你喜欢

转载自juejin.im/post/7032969935672328228
今日推荐