jiuyiUniapp/jiuyi2/components/public/jy-shop-navigation/index.vue

171 lines
4.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="tab">
<scroll-view class="scroll" scroll-x scroll-with-animation :show-scrollbar="false" :scroll-left="scrollLeft">
<view class="list" :class="scroll ? '' : 'flex-row-left'" id="tab">
<view class="item fmid ptb10 plr20" :class="{'active': index === currentIndex}" :id="'tab-item-' + index"
v-for="(item, index) in list" :key="index" @click="handleTabClick(item, index)">
{{ item[titalName] }}
</view>
</view>
</scroll-view>
</view>
</template>
<script>
export default {
props: {
list: {
type: Array,
default: () => []
},
titalName: {
type: String,
default: 'name'
},
// 是否滚动,默认是,否则是不滚动,按个数等分宽度
scroll: {
type: Boolean,
default: true
},
// 支持双向绑定的 prop
modelValue: {
type: [Number,String],
default: 0
}
},
computed: {
currentIndex: {
get() {
return this.modelValue;
},
set(newValue) {
this.$emit('update:modelValue', newValue);
}
}
},
data() {
return {
scrollLeft: 0,
componentWidth: 0, // tabs组件宽度单位为px
parentLeft: 0, // 父元素(tabs组件)到屏幕左边的距离
scrollBarLeft: 0, // 移动bar需要通过translateX()移动的距离
tabItemRectInfo: [],
barFirstTimeMove: true
};
},
watch: {
list: {
deep: true,
handler(newList, oldList) {
if (newList.length !== oldList.length) {
this.currentIndex = 0;
}
this.$nextTick(() => {
this.initialize();
});
}
},
},
mounted() {
this.initialize();
},
methods: {
initialize() {
this.getComponentRect();
this.getTabItemRect();
},
getComponentRect() {
uni.createSelectorQuery().in(this).select('#tab').fields({
size: true,
rect: true
}, (data) => {
if (data) {
this.parentLeft = data.left;
this.componentWidth = data.width;
}
}).exec();
},
getTabItemRect() {
const query = uni.createSelectorQuery().in(this);
this.list.forEach((_, index) => {
query.select(`#tab-item-${index}`).fields({
size: true,
rect: true
});
});
query.exec((data) => {
if (data) {
this.tabItemRectInfo = data;
this.scrollToActiveTab();
}
});
},
scrollToActiveTab() {
const tabInfo = this.tabItemRectInfo[this.currentIndex];
if (!tabInfo) return;
const tabWidth = tabInfo.width;
const offsetLeft = tabInfo.left - this.parentLeft;
let scrollLeft = offsetLeft - (this.componentWidth - tabWidth) / 2;
this.scrollLeft = Math.max(0, scrollLeft);
const left = tabInfo.left + tabWidth / 2 - this.parentLeft;
this.scrollBarLeft = left - this.barWidth / 2;
if (this.barFirstTimeMove) {
setTimeout(() => {
this.barFirstTimeMove = false;
}, 100);
}
},
handleTabClick(item, index) {
if (index === this.currentIndex) return;
this.currentIndex = index;
this.$emit('tabItemClick', item, index);
this.scrollToActiveTab();
}
}
};
</script>
<style lang="scss" scoped>
.tab {
position: sticky;
top: 88rpx;
left: 0;
width: 100%;
z-index: 9;
}
.scroll {
box-sizing: border-box;
height: 100%;
position: relative;
white-space: nowrap;
width: 100%;
.list {
position: relative;
width: 100%;
white-space: nowrap;
}
.item {
position: relative;
display: inline-block;
color: #8C8C8C;
&.active {
color: #333;
font-weight: bold;
transform: scale(1.1);
}
}
}
// 隐藏滚动条
::-webkit-scrollbar {
display: none;
width: 0 !important;
height: 0 !important;
-webkit-appearance: none;
background: transparent;
}
</style>