组件说明
开发项目的时候想着把所有tabs切换的功能做成组件,方便调用
功能满足项目需求就行,没有做太多的功能。使用的时候可自行增加更多功能
主要功能有
(1)是否横向滚动
(2)css样式自定义
(3)默认选中:下标0开始
组件代码非常简洁。
大致思路就是
1、在组件生命周期ready中进行赋值选中操作和滑块的位置计算。
2、点击切换tab的时候进行四步操作,(1)赋值选中项;(2)计算滑块位置;(3)计算滚动条位置;(4)绑定切换事件this.triggerEvent()
自定义组件
创建components目录
在components目录新建tabs目录
在tabs目录新建四个文件
js json wxml wxss
js文件
// getAllRect, getRect, nextTicks 这三个看下面的注释。
/*
export function nextTick(cb) {
if (wx.canIUse('nextTick')) {
wx.nextTick(cb);
}
else {
setTimeout(() => {
cb();
}, 1000 / 30);
}
}
export function getRect(context, selector) {
return new Promise((resolve) => {
wx.createSelectorQuery()
.in(context)
.select(selector)
.boundingClientRect()
.exec((rect = []) => resolve(rect[0]));
});
}
export function getAllRect(context, selector) {
return new Promise((resolve) => {
wx.createSelectorQuery()
.in(context)
.selectAll(selector)
.boundingClientRect()
.exec((rect = []) => resolve(rect[0]));
});
}
*/
import { getAllRect, getRect, nextTick } from '../../js/utils';
Component({
properties: {
list: {
type: Array,
value: []
},
customStyle: {
type: String,
value: ''
},
active:{
type:Number,
value:0
},
scrollable: {
type: Boolean,
value: true
}
},
data: {
scrollLeft: 0,
currentIndex: 0,
lineOffsetLeft: 0,
lineWidth: 40
},
lifetimes: {
//在组件在视图层布局完成后执行
ready: function () {
let that = this;
this.setData({
currentIndex:this.data.active,
scrollable: this.data.list.length <= 5 ? false : true
}, function () {
const currentIndex = that.data.currentIndex;
Promise.all([
getAllRect(this, '.cl-tab'),
getRect(this, '.cl-tabs__line'),
]).then(([rects = [], lineRect]) => {
const rect = rects[currentIndex];
if (rect == null) {
return;
}
let lineOffsetLeft = rects.slice(0, currentIndex).reduce((prev, curr) => prev + curr.width, 0);
lineOffsetLeft += (rect.width - lineRect.width) / 2;
that.setData({
lineOffsetLeft
});
});
});
}
},
methods: {
//切换组件
swich: function (e) {
const { data } = this;
const currentIndex = e.currentTarget.dataset.index;
if (currentIndex === data.currentIndex) {
return;
}
const shouldEmitChange = data.currentIndex !== null;
this.setData({ currentIndex });
nextTick(() => {
this.resize(false);
this.scrollIntoView();
if (shouldEmitChange) {
//绑定事件到change
this.triggerEvent('change', {
index: currentIndex
})
}
});
},
resize() {
const { currentIndex } = this.data;
Promise.all([
getAllRect(this, '.cl-tab'),
getRect(this, '.cl-tabs__line'),
]).then(([rects = [], lineRect]) => {
const rect = rects[currentIndex];
if (rect == null) {
return;
}
let lineOffsetLeft = rects.slice(0, currentIndex).reduce((prev, curr) => prev + curr.width, 0);
lineOffsetLeft += (rect.width - lineRect.width) / 2;
this.setData({
lineOffsetLeft
});
});
},
scrollIntoView() {
const { currentIndex, scrollable } = this.data;
if (!scrollable) {
return;
}
Promise.all([
getAllRect(this, '.cl-tab'),
getRect(this, '.cl-tabs-nav'),
]).then(([tabRects, navRect]) => {
const tabRect = tabRects[currentIndex];
const offsetLeft = tabRects
.slice(0, currentIndex)
.reduce((prev, curr) => prev + curr.width, 0);
this.setData({
scrollLeft: offsetLeft - (navRect.width - tabRect.width) / 2,
});
});
}
}
})
json文件
//启用自定义插件
{
"component": true
}
wxml文件
<--
customStyle 自定义css样式
scrollable 是否横向滚动
lineOffsetLeft 当前选择的线条偏移量
lineWidth 线条的宽度
-->
<view class="cl-tabs" style="{{customStyle}}">
<scroll-view scroll-x="{{ scrollable }}" scroll-with-animation class="" scroll-left="{{ scrollLeft }}">
<view class="cl-tabs-nav {{scrollable ? 'cl-tabs-scroll' : 'cl-tabs-noscroll'}}">
<view class="cl-tabs__line"
style="width:{{lineWidth}}px;transform:translateX({{lineOffsetLeft}}px);-webkit-transform:translateX({{lineOffsetLeft}}px);transition-duration:0.3s;-webkit-transition-duration:0.3s;">
</view>
<view wx:for="{{list}}" data-index="{{index}}" class="cl-tab {{currentIndex==index ? 'cl-tab-active' : ''}}"
catchtap="swich">{{item.title}}
</view>
</view>
</scroll-view>
</view>
wxss文件
.cl-tabs{
background-color: #ffffff;
}
.cl-tabs-scroll {
position: relative;
user-select: none;
white-space: nowrap;
}
.cl-tabs-noscroll{
display: -webkit-flex;
display: flex;
overflow: hidden;
}
.cl-tab {
position: relative;
min-width: 0;
padding: 0 20rpx;
text-align: center;
cursor: pointer;
color: #000000;
font-size: 28rpx;
line-height: 80rpx;
}
.cl-tabs-scroll .cl-tab{
display: inline-block;
padding:0 30rpx;
}
.cl-tabs-noscroll .cl-tab{
flex: 1;
}
.cl-tab-active{
font-weight: 500;
color:#f63434;
}
.cl-tabs__line {
position: absolute;
bottom: 0;
left: 0;
z-index: 1;
height: 6rpx;
background-color: #f63434;
}
如何使用
json文件中引用
wxml文件中使用
list数组
//有title属性就行
//例如
[{title:'tab1'},{title:'tab2'}]
//wxml切换事件 bind:change="tabsChange"
//在js文件中通过detail.index获取当前tab的位置 从0开始
tabsChange:function(e){
console.log(e.detail.index);
}
效果演示
不滚动
横向滚动
使用组件的时候将scrollable设置为true或者tab超过5个会自动变更为横向滚动。