template-project/components/swiper-tab/swiper-tab.vue

172 lines
4.0 KiB
Vue
Raw Normal View History

2022-03-28 10:40:02 +00:00
<template>
<view class="tabBlock" v-if="list.length > 0">
<scroll-view scroll-x="true" scroll-with-animation :scroll-left="tabsScrollLeft" @scroll="scroll">
<view class="tab" id="tab_list">
<!-- 循环体 -->
<view v-for="(item, index) in list" :key="index"
:class="['tab__item', {'tab__item--active': currentIndex === index}]"
:style="{color: (currentIndex === index ? `${itemColor}`: '')}" id="tab_item"
@click="select(item, index)">
<!-- 标题 -->
<view v-if="!showTitleSlot">{{item.title}}</view>
</view>
</view>
<!-- 下划线 -->
<view class="tab__line"
:style="{background: lineColor, width: lineStyle.width, transform: lineStyle.transform,transitionDuration: lineStyle.transitionDuration}">
</view>
</scroll-view>
</view>
</template>
<script>
export default {
props: {
value: [Number, String],
list: { // 传值
type: Array,
default: () => {
return [
{title:'标题一'},
{title:'标题二'},
{title:'标题三'},
{title:'标题四'},
{title:'标题五'},
{title:'标题六'},
{title:'标题七'},
{title:'标题八'},
{title:'标题九'},
]
}
},
itemColor: String, // tab内容颜色
lineColor: String, // 下划线颜色
lineAnimated: { // 是否展示下划线动画
type: Boolean,
default: true
}
},
data() {
return {
currentIndex: 0,
lineStyle: {},
scrollLeft: 0,
tabsScrollLeft: 0,
duration: 0.3
}
},
computed: {
showTitleSlot() {
return this.$scopedSlots.title
}
},
watch: {
list() {
this.setTabList()
},
value() {
this.currentIndex = this.value
this.setTabList()
}
},
mounted() {
this.currentIndex = this.value
this.setTabList()
if (!this.lineAnimated) {
this.duration = 0
}
console.log(this.$scopedSlots)
},
methods: {
select(item, index) {
this.$emit('changeEv', index)
2022-03-28 10:40:02 +00:00
},
setTabList() {
this.$nextTick(() => {
if (this.list.length > 0) {
this.setLine()
this.scrollIntoView()
}
})
},
setLine() {
let lineWidth = 0,
lineLeft = 0
this.getElementData(`#tab_item`, (data) => {
let el = data[this.currentIndex]
this.$emit('tabheight',el.height)
lineWidth = el.width / 2
// lineLeft = el.width * (this.currentIndex + 0.5) // 此种只能针对每个item长度一致的
lineLeft = el.width / 2 + (-data[0].left) + el.left
this.lineStyle = {
width: `${lineWidth}px`,
transform: `translateX(${lineLeft}px) translateX(-50%)`,
transitionDuration: `${this.duration}s`
};
})
},
scrollIntoView() { // item滚动
let lineLeft = 0;
this.getElementData('#tab_list', (data) => {
let list = data[0]
this.getElementData(`#tab_item`, (data) => {
let el = data[this.currentIndex]
// lineLeft = el.width * (this.currentIndex + 0.5) - list.width / 2 - this.scrollLeft
lineLeft = el.width / 2 + (-list.left) + el.left - list.width / 2 - this.scrollLeft
this.tabsScrollLeft = this.scrollLeft + lineLeft
})
})
},
getElementData(el, callback) {
uni.createSelectorQuery().in(this).selectAll(el).boundingClientRect().exec((data) => {
callback(data[0]);
});
},
scroll(e) {
this.scrollLeft = e.detail.scrollLeft;
}
}
}
</script>
<style lang="scss">
.tabBlock {
position: relative;
background: #fff;
.tab {
position: relative;
display: flex;
font-size: 28rpx;
padding-bottom: 15rpx;
white-space: nowrap;
&__item {
// flex: 1;
// width: 20%;
padding: 0 20rpx;
2022-03-28 10:40:02 +00:00
flex-shrink: 0;
text-align: center;
line-height: 90rpx;
color: #868695;
&--active {
color: $uni-color-primary;
font-weight: bold;
}
&-title {
margin: 0 40rpx;
}
}
}
.tab__line {
display: block;
height: 6rpx;
position: absolute;
bottom: 20rpx;
left: 0;
z-index: 1;
border-radius: 6rpx;
position: relative;
background: $uni-color-primary;
}
}
</style>