「这是我参与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
属性,让我们用更少的代码可以实现平滑偏移效果:
- 组件内自身优化了偏移滑动效果
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个,其余参数可自行按需载入