You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

290 lines
6.8 KiB

<template>
<aside class="sidebar">
<ul>
<li v-for="(item, index) in menuList" :key="item.path + random()">
<div
:class="[($route.path == item.path) || (item.noToPath && curIndex == index) ? 'active' : '', 'flex', ($route.path == item.path) ? curIndex = index : '']">
<!-- @click="gotoPath(item, index)" 暂时先注释 -->
<SvgIcon1 :iconPath="require(`@/assets/${item.img}`)" defaultColor="#8A9099" :size="16" activeColor="#006AFF"
:isActive="($route.path == item.path || (item.noToPath && curIndex == index))" />
<span class="title_text">{{ item.name }}</span>
</div>
<p :class="['flex', activeFloor == item1.desc ? 'curActive' : '']" v-for="(item1) in item.list"
@click="setActiveCur(item1.desc, item)" :key="item1.name">{{ item1.name }}</p>
</li>
</ul>
</aside>
</template>
<script>
import SvgIcon1 from '@/components/SvgIcon1.vue';
// :class="[$route.path != item.path ? 'not-point' : '', 'flex', activeFloor == item1.desc ? 'curActive' : '']"
import { mapState } from 'vuex';
import store from '../store';
export default {
name: 'Sidebar',
props: {
menuList: {
type: Array,
required: true
},
// activeFloor:{
// type:String
// },
// curIndex:{
// type:Number
// }
},
components: {
SvgIcon1,
},
data() {
return {
activeFloor: null,
curIndex: 0,
scrollLock: false,
}
},
watch: {
'$route'(to, from) {
console.log(to, from);
// 路由变化时重新计算位置
this.$nextTick(() => {
this.calculateFloorOffsets();
this.handleScroll(); // 立即检查当前位置
});
}
},
mounted() {
this.activeFloor = this.menuList[this.curIndex]?.list?.[0]?.desc;
this.$nextTick(() => {
// 更可靠的获取滚动容器方式
this.scrollContainer = document.querySelector('.main-content') ||
document.getElementById('main-content') ||
window;
if (this.scrollContainer) {
this.scrollContainer.addEventListener('scroll', this.handleScroll);
this.calculateFloorOffsets();
} else {
console.error('未找到滚动容器');
}
});
},
beforeDestroy() {
if (this.scrollContainer) {
this.scrollContainer.removeEventListener('scroll', this.handleScroll);
}
},
created() {
// console.log(this.$parent.$refs.scrollContainer,'this.$refs.sc--rollContainer--');
},
computed: {
...mapState(['pageTitle']) // 从Vuex映射showSidebar状态到组件的计算属性中
},
methods: {
random() {
var randomNumber = Math.random();
return randomNumber
},
calculateFloorOffsets() {
this.menuList.forEach(item => {
item.list?.forEach(every => {
const el = document.getElementById(every.desc);
if (el) {
// 获取元素相对于视口顶部的距离
every.offsetTop = el.getBoundingClientRect().top + window.pageYOffset;
}
});
});
},
handleScroll() {
if (this.scrollLock || !this.menuList[this.curIndex]?.list) return;
const scrollPosition = this.getScrollPosition();
let activeFloor = null;
// 从下往上查找当前可见区域对应的楼层
for (let i = this.menuList[this.curIndex].list.length - 1; i >= 0; i--) {
const item = this.menuList[this.curIndex].list[i];
if (scrollPosition + 100 >= (item.offsetTop || 0)) { // 100是提前量
activeFloor = item.desc;
break;
}
}
if (activeFloor && this.activeFloor !== activeFloor) {
this.activeFloor = activeFloor;
}
},
getScrollPosition() {
if (this.scrollContainer === window) {
return window.pageYOffset || document.documentElement.scrollTop;
}
return this.scrollContainer.scrollTop;
},
// setActiveCur(dom, item) {
// if (this.$route.path != item.path) {
// this.$router.push(item.path)
// store.commit('SET_PAGETITLE', item.name);
// }
// setTimeout(() => {
// this.activeFloor = dom;
// this.setHighActive(dom)
// }, 500)
// },
// setHighActive(dom) {
// this.scrollLock = true;
// const ele = document.getElementById(dom)
// if (!ele) return
// ele.classList.add('ceshi')
// ele.scrollIntoView({ behavior: 'smooth', block: 'start' })
// setTimeout(() => {
// ele.classList.remove('ceshi')
// }, 1000)
// }
gotoPath(item, index) {
let path = item.path;
if (!path) {
this.curIndex = index;
return
}
if (this.$route.path != path) {
this.curIndex = index
this.scrollLock = false;
this.handleScroll()
// 重置页面滚动高度
const dom = document.getElementById('main-content')
dom.scrollTop = 0;
this.$router.push(path)
}
},
activeArea(type) {
console.log(type);
},
setActiveCur(dom, item) {
debugger
if (this.$route.path !== item.path) {
this.$router.push(item.path);
store.commit('SET_PAGETITLE', item.name);
}
this.scrollLock = true;
this.activeFloor = dom;
this.$nextTick(() => {
this.setHighActive(dom);
setTimeout(() => {
this.scrollLock = false;
}, 1000);
});
},
setHighActive(dom) {
const ele = document.getElementById(dom);
if (ele) {
ele.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
}
}
}
}
</script>
<style scoped lang="scss">
.sidebar {
min-width: 158px;
padding: 21px;
box-sizing: border-box;
background: #FFFFFF;
box-shadow: 0px 0px 11px 2px rgba(147, 147, 147, 0.11);
}
.ceshi {
// animation: fadeInOut 2s infinite;
}
.title_text {
margin-left: 6px;
}
ul {
list-style: none;
padding: 0;
}
.not-point {
pointer-events: none;
/* 阻止鼠标事件 */
opacity: 0.5;
/* 可选降低透明度以视觉上表示不可用 */
cursor: not-allowed;
/* 改变鼠标光标样式表示不可用 */
}
li {
margin-bottom: 10px;
div {
letter-spacing: 0.08em;
color: #1E2226;
// margin: 12px 0;
height: 40px;
cursor: pointer;
img {
margin-right: 6px;
}
}
p {
letter-spacing: 0.08em;
line-height: 18px;
height: 36px;
color: #8A9099;
cursor: pointer;
&:hover {
color: #006AFF;
}
}
.curActive {
color: #006AFF;
}
}
/* {
display: block;
padding: 8px 12px;
text-decoration: none;
color: #333;
border-radius: 4px;
} */
/*
:hover {
background: #e0e0e0;
} */
.active {
font-weight: bold;
letter-spacing: 0.08em;
color: #006AFF;
}
.item-active {
color: #006AFF;
}
/*
.exact-active {
background: #1976d2;
color: white;
} */
</style>