需求:
- 插槽为动态, 可以在使用页面自行设置
- 可以自定义设置每个tab的样式, 也可以设置容器的样式
- 如果tab太多, 容器可以横向滚动
- 设置当前tab值可以自动定位到当前tab位置
思路:
- slot属性name动态设置
- 设置默认样式, 写好公共的方法, 将对象转换成style可以用的字符串
- scroll-x
- scroll-into-view
组件代码 ⬇️
wxml
<view class="tabs-container">
<scroll-view style="{{tabsConStyle}}" class="pane-con" scroll-x enhanced bounces scroll-into-view="{{currentTab}}">
<view wx:for="{{tabs}}" wx:key="id" id="{{item.id}}" class="tabs-pane inline {{index === activeTab ? 'active' : ''}}" style="{{index === activeTab ? paneActiveStyle : paneStyle}}" bindtap="switchTab" data-index="{{index}}">{{item.label}}</view>
</scroll-view>
<block wx:for="{{tabs}}" wx:key="id">
<!-- 可以使用每项对应的插槽 -->
<view class="tabs-content" wx:if="{{activeTab === index}}">
<slot name="{{index}}"></slot>
</view>
<!-- 如果使用页面中每tab只是数据不同或其它情况, 也可以使用这个默认插槽 -->
<slot></slot>
</block>
</view>
js
Component({
options: {
multipleSlots: true
},
properties: {
// 必传参: tabs数组, 每项需要传一个包含属性名为label和属性名为id唯一值的对象
tabs: {
required: true,
type: Array,
value: () => {
return [{
label: "",
id: ""
}]
}
},
// 非必传: 当前tab初始值
activeTab: {
type: Number,
value: 0
},
// 非必传: 每一项的样式
tabStyle: Object,
// 非必传: 当前项的样式
tabActiveStyle: Object,
// 非必传: 可滑动tabs容器的样式
tabsStyle: Object,
},
data: {
paneStyle: "",
paneActiveStyle: "",
tabsConStyle: "",
flag: false,
// 为固定tabCon左滑的位置
currentTab: "",
},
methods: {
initTabs() {
// 共三个参数的赋值过程
// 思路:
// 1. 都需要经过对象转字符串过程
// 2. 如果有普通每项, 则先将当前项的特殊样式与普通项样式合并, 再进行字符串处理
this.setData({
paneStyle: this.transferObjToStr(this.data.tabStyle),
paneActiveStyle: this.data.tabStyle ? this.transferObjToStr(Object.assign(this.data.tabStyle, this.data.tabActiveStyle)) : this.transferObjToStr(this.data.tabActiveStyle),
tabsConStyle: this.transferObjToStr(this.data.tabsStyle),
})
},
switchTab(event) {
// 切换方法: 设置当前项, 并传值
this.setData({
activeTab: event.currentTarget.dataset.index,
})
this.triggerEvent('switchTab', this.data.activeTab);
},
transferObjToStr(obj) {
// 小程序中style不可以像VUE一样直接使用对象, 而传入的是对象, 这一步是将传入的style对象转换成组件中可以直接使用的字符串
if (!obj) return "";
let str = "";
for (let key in obj) {
str += `${key}: ${obj[key]};`;
}
return str;
},
},
lifetimes: {
attached() {
this.initTabs();
}
},
observers: {
tabs: function (tabs) {
// 将来可能会做tabs增删改的功能(我自己想的哈哈哈哈哈)这步的意思是头一次进入页面才需要判断有无activeTab
// 单拿出来监听tabs: activeTab的设置, 必须得在tabs赋值之后
if (this.data.flag) return;
if (tabs.length > 0) {
// 代表tabs赋值完毕
this.setData({
flag: true,
// 自动定位当前tab
currentTab: this.data.activeTab === 0 ? "" : this.data.tabs[this.data.activeTab].id
})
}
}
},
})
wxss
/* 样式重点是这个容器: 宽度为本身容器的100%, 横向溢出滑动并且不能换行 */
.pane-con {
width: 100%;
overflow-x: scroll;
overflow-y: hidden;
white-space: nowrap;
}
/* 取消滚动条展示 */
.pane-con::-webkit-scrollbar {
display: none;
}
.inline {
display: inline-block;
}
.tabs-pane {
padding: 10rpx 20rpx;
margin-right: 16rpx;
border: 1px solid lightgrey;
border-radius: 8rpx;
transition: all .1s ease-in;
}
.tabs-pane:nth-last-child(1) {
margin-right: 0;
}
.tabs-pane.active {
background: #5495df;
border-color: #5495df;
color: #fff;
}
使用页面代码就不放了因为是正在研发的项目, 按照注释设置参数即可.
需要传当前值的时候用trigger.event的方法将值传出去接收即可~
tada~~~一个自定义的tab就完成啦
网友评论