废话不多说,先上效果图
1. 先新建一个用来存放tabs的文件
tabs.wxml
<scroll-view scroll-x="{{true}}" class="scroll" scroll-left="{{transscr}}" scroll-with-animation="{{true}}">
<block wx:for="{{items}}" wx:key="_this">
<view class="scroll_item" style="{{idx==index?'font-weight: bold;transform: scale(1.1);':''}}" bind:tap="switchover" data-index="{{index}}">{{item.name}}</view>
</block>
<view class="scroll_glide" style="width:{{transwidth}}px;transform: translateX({{transx}}px);">
<view class="scroll_view"></view>
</view>
</scroll-view>
tabs.js
Component({
/**
* 组件的初始数据
*/
data: {
// 子元素的距离
transx: 0,
// 设置宽度
transwidth: 0,
// 子元素距离左边位置
element: [],
// 子元素宽度
element_width: [],
// 距离左边
transscr: 0
},
// 父组件传值
properties: {
items: null,
idx: {
type: Number,
value: 0,
observer: function (newVal, oldVal, changedPath) {
let newlist = {
currentTarget: {
dataset: {
index: newVal
}
}
}
this.switchover(newlist);
}
}
},
/**
* 组件的初始数据方法
*/
ready() {
let _this = this;
let _list = [];
let _width = [];
_this.createSelectorQuery().selectAll('.scroll_item').boundingClientRect(function (rects) {
rects.forEach(function (rect) {
_list.push(rect.left - 12); //这里减12是因为我在css里写了一个padding-left:24rpx;
_width.push(rect.width);
})
_this.setData({
element: _list,
transwidth: _width[0],
element_width: _width
})
}).exec();
},
/**
* 组件的方法列表
*/
methods: {
switchover({
currentTarget
}) {
// 获取子元素距离左边的距离的集合
let distance = this.data.element;
// 获取子元素的宽度
let width = this.data.element_width;
// 获取索引
let idx = currentTarget.dataset.index;
// 获取屏幕宽度
let screenHalfWidth = this.data.screenHalfWidth;
// 赋值
this.setData({
transx: distance[idx],
transwidth: width[idx],
transscr: distance[idx] - (width[idx] / 2),
idx: idx
})
// 给父组件传值
this.triggerEvent('parentEvent', {
index: idx
})
}
}
})
当子组件需要传值的时候就需要在子组件的json里加入
"component": true
tabs.wxss
.scroll {
height: 80rpx;
width: 750rpx;
background: #ffffff;
white-space: nowrap;
padding-left: 24rpx;
box-sizing: border-box;
}
.scroll_item {
display: inline-flex;
margin-right: 30rpx;
height: 70rpx;
line-height: 70rpx;
font-size: 26rpx;
transition: .3s;
}
.scroll_view {
width: 30rpx;
height: 6rpx;
background: #12299e;
}
.scroll_glide{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
transition: .3s;
}
2. 然后我们在父组件中调取这个组件
"usingComponents": {
"z-tabs": "../../component/tabs/tabs"
}
父组件wxml中写入
<view class="mer_tabs">
<z-tabs items="{{tab_items}}" idx="{{tab_idx}}" bind:parentEvent='onTapChild'></z-tabs>
</view>
父组件的css
.mer_tabs {
position: sticky; /*这里是让他漂浮在上面的*/
top: 0;
z-index: 99;
}
父组件的js
data:{
//tabs
tab_items: [],
tab_idx: 0 //因为一会要写自适应的swiper
}
// 子组件传值了
onTapChild({ detail }) {
let list = this.data.arrlist_height //这里主要是用来适配下面swiper的,如若不用,删了即可
this.setData({
tab_idx: detail.index,
arrheight: list[detail.index]
})
},
3.swiper的自适应
<!-- 底部列表 -->
<swiper style="height:{{arrheight}}px" bindanimationfinish='changeGoodsSwip' bindchange="SwiperChange" current="{{tab_idx}}" duration="300">
<swiper-item wx:for="{{tab_items}}" wx:key='_this' wx:for-item="tabs">
<view class="lists">
<block wx:for="{{array}}" wx:key="_this">
<view></view> <!--这里写自己的内容就好了-->
</block>
</view>
</swiper-item>
</swiper>
js中
data: {
// 底部列表
array: ["", "", "", "", "", "", ""],
// 获取底部高度进行自适应
arrheight: 0,
// 高度列表
arrlist_height: []
},
onLoad: function (options) {
let _this = this;
let listheight = [];
// 这里是获取.lists的高度后然后push进一个数组中去
setTimeout(function () {
wx.createSelectorQuery().selectAll('.lists').boundingClientRect(function (rects) {
rects.forEach(res => {
listheight.push(res.height)
});
_this.setData({
arrheight: listheight[0],
arrlist_height: listheight
})
}).exec();
}, 500)
},
// 子组件传值了
onTapChild({detail}) {
let list = this.data.arrlist_height
this.setData({
tab_idx: detail.index,
arrheight: list[detail.index]
})
},
// 滑动改变了current
SwiperChange(event) {
let list = this.data.arrlist_height;
this.setData({
tab_idx: event.detail.current,
arrheight: list[event.detail.current]
})
},
// 这里是防止swiper卡死
changeGoodsSwip(event) {
if (event.detail.source == "touch") {
if (event.detail.current == 0) {
//有时候这算是正常情况,所以暂定连续出现3次就是卡了
let swiperError = this.data.swiperError
swiperError += 1
this.setData({
swiperError: swiperError
})
if (swiperError >= 3) { //在开关被触发3次以上
this.setData({
tab_idx: this.data.preIndex
}); //,重置current为正确索引
this.setData({
swiperError: 0
})
}
} else { //正常轮播时,记录正确页码索引
this.setData({
preIndex: event.detail.current
});
//将开关重置为0
this.setData({
swiperError: 0
})
}
}
}
附上所有代码
父组件
<view class="mer_tabs">
<z-tabs items="{{tab_items}}" idx="{{tab_idx}}" bind:parentEvent='onTapChild'></z-tabs>
</view>
<!-- 底部列表 -->
<swiper style="height:{{arrheight}}px" bindanimationfinish='changeGoodsSwip' bindchange="SwiperChange" current="{{tab_idx}}" duration="300">
<swiper-item wx:for="{{tab_items}}" wx:key='_this' wx:for-item="tabs">
<view class="lists">
<block wx:for="{{array}}" wx:key="_this">
<view></view>
</block>
</view>
</swiper-item>
</swiper>
const app = getApp();
Page({
/**
* 页面的初始数据
*/
data: {
//tabs
tab_items: [],
tab_idx: 0,
// 底部列表
array: ["", "", "", "", "", "", ""],
// 获取底部高度进行自适应
arrheight: 0,
// 高度列表
arrlist_height: []
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
let _this = this;
let listheight = [];
setTimeout(function () {
wx.createSelectorQuery().selectAll('.lists').boundingClientRect(function (rects) {
rects.forEach(res => {
listheight.push(res.height)
});
_this.setData({
arrheight: listheight[0],
arrlist_height: listheight
})
}).exec();
}, 500)
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
// 子组件传值了
onTapChild({
detail
}) {
let list = this.data.arrlist_height
this.setData({
tab_idx: detail.index,
arrheight: list[detail.index]
})
},
// 滑动改变了current
SwiperChange(event) {
let list = this.data.arrlist_height;
this.setData({
tab_idx: event.detail.current,
arrheight: list[event.detail.current]
})
},
changeGoodsSwip(event) {
if (event.detail.source == "touch") {
if (event.detail.current == 0) {
//有时候这算是正常情况,所以暂定连续出现3次就是卡了
let swiperError = this.data.swiperError
swiperError += 1
this.setData({
swiperError: swiperError
})
if (swiperError >= 3) { //在开关被触发3次以上
this.setData({
tab_idx: this.data.preIndex
}); //,重置current为正确索引
this.setData({
swiperError: 0
})
}
} else { //正常轮播时,记录正确页码索引
this.setData({
preIndex: event.detail.current
});
//将开关重置为0
this.setData({
swiperError: 0
})
}
}
}
})
{
"usingComponents": {
"z-tabs": "../../component/tabs/tabs"
}
}
子组件
<scroll-view scroll-x="{{true}}" class="scroll" scroll-left="{{transscr}}" scroll-with-animation="{{true}}">
<block wx:for="{{items}}" wx:key="_this">
<view class="scroll_item" style="{{idx==index?'font-weight: bold;transform: scale(1.1);':''}}" bind:tap="switchover" data-index="{{index}}">{{item.name}}</view>
</block>
<view class="scroll_glide" style="width:{{transwidth}}px;transform: translateX({{transx}}px);">
<view class="scroll_view"></view>
</view>
</scroll-view>
Component({
/**
* 组件的初始数据
*/
data: {
// 子元素的距离
transx: 0,
// 设置宽度
transwidth: 0,
// 子元素距离左边位置
element: [],
// 子元素宽度
element_width: [],
// 距离左边
transscr: 0
},
// 父组件传值
properties: {
items: null,
idx: {
type: Number,
value: 0,
observer: function (newVal, oldVal, changedPath) {
let newlist = {
currentTarget: {
dataset: {
index: newVal
}
}
}
this.switchover(newlist);
}
}
},
/**
* 组件的初始数据方法
*/
ready() {
let _this = this;
let _list = [];
let _width = [];
_this.createSelectorQuery().selectAll('.scroll_item').boundingClientRect(function (rects) {
rects.forEach(function (rect) {
_list.push(rect.left - 12);
_width.push(rect.width);
})
_this.setData({
element: _list,
transwidth: _width[0],
element_width: _width
})
}).exec();
},
/**
* 组件的方法列表
*/
methods: {
switchover({
currentTarget
}) {
// 获取子元素距离左边的距离的集合
let distance = this.data.element;
// 获取子元素的宽度
let width = this.data.element_width;
// 获取索引
let idx = currentTarget.dataset.index;
// 获取屏幕宽度
let screenHalfWidth = this.data.screenHalfWidth;
// 赋值
this.setData({
transx: distance[idx],
transwidth: width[idx],
transscr: distance[idx] - (width[idx] / 2),
idx: idx
})
// 给父组件传值
this.triggerEvent('parentEvent', {
index: idx
})
}
}
})
{
"component": true,
"usingComponents": {}
}
.scroll {
height: 80rpx;
width: 750rpx;
background: #ffffff;
white-space: nowrap;
padding-left: 24rpx;
box-sizing: border-box;
}
.scroll_item {
display: inline-flex;
margin-right: 30rpx;
height: 70rpx;
line-height: 70rpx;
font-size: 26rpx;
transition: .3s;
}
.scroll_view {
width: 30rpx;
height: 6rpx;
background: #12299e;
}
.scroll_glide{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
transition: .3s;
}
可能有些BUG,暂时没测试到,希望测试到的提意见我会修改的