Vue 轻量级滑动tab栏_选中的item自动居中组件
可滑动,选定的tabItem自动居中,支持x和y两种模式
<template>
<div class="scrollBarWrapper" :style="scrollBarWrapperStyle">
<div
class="scrollBarContent"
:class="direction === 'y' ? 'directionY' : 'directionX'"
ref="scrollBarContent"
>
<slot></slot>
</div>
</div>
</template>
<script>
export default {
props: {
direction: {
type: String,
default: "x",
validator(value) {
return value === "x" || value === "y";
}
},
activeIndex: {
type: Number,
default: 0,
validator(value) {
return value >= 0;
}
}
},
watch: {
activeIndex(newVal, oldVal) {
this.handleChange();
}
},
computed: {
scrollBarWrapperStyle() {
return this.direction === "y"
? {
height: "100%"
}
: {
width: "100%"
};
}
},
mounted() {
this.initItemDisplay();
this.handleChange();
},
methods: {
initItemDisplay() {
const content = this.$refs.scrollBarContent;
const contentItem = content.children;
[].forEach.call(contentItem, item => {
if (this.direction === "y") {
item.style.display = "block";
} else {
item.style.display = "inline-block";
}
});
},
handleChange() {
this.$nextTick(() => {
const content = this.$refs.scrollBarContent; // 发生滑动的元素
const activeItem = content.children[this.activeIndex]; // 当前选中的元素
if(!activeItem) return false;
const scrollOption = {
top: 0,
left: 0,
behavior: "smooth"
};
if (this.direction === "y") {
const contentHeight = content.offsetHeight;
const activeItemHeight = activeItem.offsetHeight;
const activeItemTop = activeItem.offsetTop;
const offset = activeItemTop - (contentHeight - activeItemHeight) / 2; // 需要移动的位置
scrollOption.top = offset;
} else {
const contentWidth = content.offsetWidth; // 发生滑动元素的宽
const activeItemWidth = activeItem.offsetWidth; // 当前元素的宽
const activeItemLeft = activeItem.offsetLeft; // 当前元素的到他父盒子左侧的距离
const offset = activeItemLeft - (contentWidth - activeItemWidth) / 2; // 需要移动的位置
scrollOption.left = offset;
}
content.scrollTo(scrollOption);
});
}
}
};
</script>
<style lang="scss" scoped>
.scrollBarWrapper {
position: relative;
overflow: hidden;
user-select: none;
vertical-align: middle;
.scrollBarContent {
width: 100%;
white-space: nowrap;
word-break: keep-all;
-webkit-overflow-scrolling: touch;
&.directionX {
overflow-x: scroll;
overflow-y: hidden;
}
&.directionY {
overflow-x: hidden;
overflow-y: scroll;
height: 100%;
}
&::-webkit-scrollbar {
display: none;
}
}
}
</style>
demo
<template>
<scrollBar direction="x" :activeIndex="activeIndex">
<div
class="scrollBarItem"
v-for="(item, index) in options"
:key="index"
@click="changeNav(item, index)"
:class="index === activeIndex ? 'active' : null"
>
<div>{{item.name}}</div>
</div>
</scrollBar>
</template>
<script>
// 先导入再注册下
export default {
data() {
return {
activeIndex: 0,
options: [
{id: 1, name: '关注'},
{id: 2, name: '推荐'},
{id: 3, name: '本地'},
{id: 4, name: '新闻'},
{id: 5, name: '汽车'},
{id: 6, name: '直播'},
{id: 7, name: '游戏'},
{id: 8, name: '小说'},
{id: 9, name: '美女'}
]
}
},
methods: {
changeNav(item, index) {
this.activeIndex = index;
}
}
}
</script>
<style lang="scss" scoped>
.scrollBarItem {
padding: rem(8) rem(15);
}
.active {
color: red;
div {
border-bottom: 1px solid red;
}
}
</style>
为之则易,不为则难。