记录一个vue侧边导航栏组件,可以与内容联动,话不多说上代码:
html:
<template>
<div class="app">
<div class="nav" id="box_action_translateYOut">
<div class="nav_box" v-for="(item, index) in stepList" :key="index" :class="{ navActive: currentIndex === index }">
<div v-show="currentIndex !== index"></div>
<svg-icon v-show="currentIndex === index" class-name="fswx-icon" icon-class="fswx-selected" />
<a :href="'#' + item.value" @click="goStep(item.value)">{{ item.name }}</a>
</div>
<div class="fswx-switch-btn">
<a :href="'#' + id" @click="goLastStep">
<svg-icon class-name="fswx-icon" icon-class="fswx-top-switch" />
</a>
<a :href="'#' + id" @click="goNestStep">
<svg-icon class-name="fswx-icon" icon-class="fswx-bottom-switch" />
</a>
</div>
</div>
</div>
</template>
js:
export default {
props: {
stepList: {
type: Array,
default: () => {
return []
}
}
},
data() {
return {
currentIndex: 0,
heightArr: [],
id: 0,
stopScroll: false
}
},
methods: {
wrapListener() {
// 获取wrap元素里所有的a标签元素
const wrapDom = document.getElementById('box_action_translateYOut')
const aDom = wrapDom.getElementsByTagName('a')
const len = aDom.length - 2
const wrap = this.$parent.$refs.wrap
const parentRefs = this.$parent.$parent.$refs
const diff = parentRefs.scrollOne.offsetTop
for (const key in parentRefs) {
if (Object.hasOwnProperty.call(parentRefs, key)) {
const element = parentRefs[key]
if (element && element.offsetTop) {
this.heightArr.push(element.offsetTop - diff)
}
}
}
// wrap可视区域高度
const domHeight = wrap.clientHeight
// wrap的滚动条的总高度
const scrollHeight = wrap.scrollHeight
window.addEventListener(
'scroll',
() => {
const scrollTop = wrap.scrollTop
for (let i = 0; i < len; i++) {
if (scrollTop > this.heightArr[i] && scrollTop < this.heightArr[i + 1] && i < len - 1) {
this.currentIndex = i
} else if (i === len - 1) {
// 最后一项
if (scrollTop > this.heightArr[i]) {
this.currentIndex = i
}
}
}
// 滚动到底部的条件
if (scrollTop + domHeight === scrollHeight) {
this.currentIndex = len - 1
}
if (this.stopScroll) {
this.currentIndex = this.id - 1
}
this.stopScroll = false
},
true
)
},
goStep(id) {
this.id = id
this.stopScroll = true
this.currentIndex = id - 1
},
goLastStep() {
if (this.currentIndex > 0) {
this.id = this.currentIndex
this.currentIndex = this.currentIndex - 1
this.stopScroll = true
}
},
goNestStep() {
if (this.id < 9) {
this.id = this.currentIndex + 2
this.currentIndex = this.currentIndex + 1
this.stopScroll = true
}
}
},
mounted() {
this.wrapListener()
}
}
css:
.app {
.nav {
width: 142px;
position: fixed;
bottom: 4%;
right: 50px;
z-index: 99;
.nav_box {
display: flex;
margin-bottom: 15px;
position: relative;
cursor: pointer;
div {
width: 6px;
height: 6px;
border-radius: 6px;
background-color: #000;
margin-right: 9px;
margin-top: 3px;
}
a {
display: inline-block;
width: 126px;
font-size: 16px;
color: #303133;
text-decoration: none;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.nav_box::after {
content: '';
width: 1px;
height: 25px;
background-color: #d8d8d8;
position: absolute;
left: 2%;
bottom: 85%;
}
.nav_box:nth-child(1)::after {
content: '';
width: 0;
height: 0;
background-color: #d8d8d8;
position: absolute;
left: 4%;
bottom: 10%;
}
// 点击导航的高亮样式
.navActive {
display: flex;
margin-bottom: 15px;
cursor: pointer;
.fswx-icon {
font-size: 10px;
margin-right: 6px;
margin-top: 2px;
margin-left: -2px;
z-index: 9;
@include theme_color;
}
a {
display: inline-block;
width: 126px;
font-size: 16px;
@include theme_color;
// color: #2d54b8;
text-decoration: none;
font-weight: 700;
}
}
.fswx-switch-btn {
position: absolute;
top: 50%;
right: -24px;
margin-top: -28px;
border: 1px solid #e4e4e4;
border-radius: 9px;
a:nth-child(1) {
border-bottom: 1px solid #e4e4e4;
}
.fswx-icon {
font-size: 9px;
padding: 3px;
}
a {
cursor: pointer;
text-decoration: none;
display: block;
color: #606266;
}
}
}
}
效果: