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.
 
 
 
 

360 lines
12 KiB

<template>
<el-collapse v-model="activeNames" @change="handleChange">
<el-collapse-item v-for="(item, index) in menuList" :key="index" :name="item[renderKeyNew.domName]">
<template #title>
<!-- <div class="flex gap8" @click.stop="handleTitleClick"> -->
<div class="flex-between gap8 collapse-item">
<div class="flex gap8 ">
<GuipToolTip :content="item[renderKeyNew.menuTitle]">
<div class="flex gap8 menu-name"><img width="20px" :src="require('@/assets/serviceIcon/ver_'+item.type+'.svg')" alt=""><span >{{ item[renderKeyNew.menuTitle] }}</span></div>
</GuipToolTip>
<!-- <span v-if="item[renderKeyNew.selected]" class="menu-select"></span> -->
</div>
<div class="flex gap8">
<span v-if="item[renderKeyNew.selected]" class="menu-select"></span>
<img class="arrow_img" :class="{ 'is-active': activeNames.includes(item[renderKeyNew.domName]) }"
src="@/assets/input_ex_ic.png" alt="">
</div>
</div>
</template>
<div v-for="(item1, index1) in item.list" @click="setActiveCur(item1, item, index)"
:class="['flex-between point gap8', activeFloor == item1[renderKeyNew.subtitle] ? 'curActive' : '']"
:key="index1">
<span class="l-menu-name">{{ item1[renderKeyNew.subtitle] }}</span>
<img v-if="item1[renderKeyNew.SubSelected]" class="selected" src="../assets/menu/is_selected.png" alt="">
</div>
</el-collapse-item>
</el-collapse>
</template>
<script>
import store from '../store';
import GuipToolTip from "@/components/GuipToolTip.vue";
export default {
options: { styleIsolation: "shared" },
props: {
menuData: {
type: [Array, Object],
required: true
},
// �续如果渲染的值���以通过调整这个修改�值
renderKey: {
type: [Object],
default: () => {}
}
},
data() {
return {
activeNames: [],//获�到的值 � 绑定的name属性
curIndex: 0,
activeFloor: '',
scrollLock: false,
componentsName: ''
};
},
computed: {
// 处�options为空的情况
menuList() {
let flag = Array.isArray(this.menuData || []);
let data = this.menuData || []
if (!flag) {
data = Object.values(this.menuData)
return data
}
return this.menuData;
},
renderKeyNew() {
return Object.assign({
menuTitle: 'name',//渲染标题
subtitle: 'name',//二级标题
selected: 'is_select',//大标题:是�展示绿色状�
SubSelected: 'is_select',//二级标题:是�展示绿色状�
domName: 'type',//未�获�dom绑定��
domAppend: 'section_' //dom �缀
// �续获�dom =》 domAppend + domName 在元素上绑定的 id�称
}, this.renderKey);
}
},
components: {
GuipToolTip
},
watch: {
menuList:{
handler(newVal, oldVal) {
// �次加载或强制刷新时,oldVal为空
if (!oldVal || oldVal.length === 0) {
this.setDefaultActive(newVal);
return;
}
console.log(newVal,'newVal===');
// 检查当�高亮的��项是��然存在于新的menuList中
const currentItemExists = this.checkCurrentItem(newVal);
console.log(currentItemExists,'currentItemExists--');
// �存在默认高亮第一项
if (!currentItemExists) {
this.setDefaultActive(newVal);
}
},
immediate: true
}
},
mounted() {
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);
}
},
methods: {
checkCurrentItem(newMenuList) {
const subtitle = this.renderKeyNew.subtitle;
// 如果当�没有高亮的��项,返回
if (!this.activeFloor) return false;
// �历新的menuList,先检查高亮的��项是�存在
for (const item of newMenuList) {
if (item.list) {
const found = item.list.some(subItem =>
subItem[subtitle] === this.activeFloor ||
subItem.componentsName === this.activeFloor
);
if (found) return true;
}
}
return false;
},
setDefaultActive(menuList) {
// 设置默认高亮项
if (menuList && menuList.length > 0 && menuList[0].list && menuList[0].list.length > 0) {
const subtitle = this.renderKeyNew.subtitle;
this.activeFloor = menuList[0].list[0][subtitle] || menuList[0].list[0]?.componentsName || '';
this.componentsName = menuList[0].list[0]?.componentsName || '';
store.commit('SET_CURRENTMENUITEM', menuList[0].list[0]);
this.curIndex = 0;
}
},
handleChange(val) {
console.log("��状��化:", val);
},
handleTitleClick() {
console.log("标题点击");
},
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;
console.log(this.curIndex, scrollPosition, 'this.curIndex===');
// 从下往上查找当���区域对应的楼层
// 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;
// }
// }
// 从上往下
for (let i = 0; i < this.menuList[this.curIndex].list.length; 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)
// }
setActiveCur(item1, item, index) {
store.commit('SET_CURRENTMENUITEM', item1);
this.curIndex = index;
let subtitle = this.renderKeyNew.subtitle;
let domName = this.renderKeyNew.domName;
let componentsName = item1?.componentsName;
// 如果采用的是 组件切�显示的办法
if (componentsName) {
this.activeFloor = componentsName;
// �步 当�切�的组件�称
store.commit('SET_COMPONENTS_NAME', componentsName);
return
}
this.scrollLock = true;
this.activeFloor = item1[subtitle];
this.$nextTick(() => {
this.setHighActive(item1[domName]);
setTimeout(() => {
this.scrollLock = false;
}, 1000);
});
},
setHighActive(dom) {
const ele = document.getElementById(this.renderKeyNew.domAppend + dom);
if (ele) {
ele.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
}
}
}
};
</script>
<style scoped lang="scss">
/* èªå®šä¹æŠ˜å å¾æ  */
::v-deep .el-collapse-item__header .el-collapse-item__arrow {
display: none !important;
}
::v-deep .el-collapse-item__header {
max-width: 162px;
}
.arrow_img {
width: 14px;
height: 14px;
}
.arrow_img.is-active {
transform: rotate(90deg);
}
.collapse-item {
width: 100%;
}
.menu-name {
font-size: 14px;
font-weight: normal;
letter-spacing: 0.08em;
color: #1E2226;
padding: 11px 0;
height: 40px;
line-height: 18px;
width: 120px;
// max-width: 96px;
box-sizing: border-box;
span{
// max-width: 50px;
// width: 50px;
text-align: left;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
.l-menu-name {
// max-width: 90px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
color: #8A9099;
padding: 7px 0;
height: 36px;
box-sizing: border-box;
}
.curActive {
.l-menu-name {
color: #006AFF;
font-weight: bold;
}
}
.menu-select {
width: 8px;
height: 8px;
border-radius: 100%;
background: #00C261;
}
.el-collapse {
min-width: 200px;
max-width: 200px;
background-color: #fff;
height: 100%;
overflow-y: auto;
padding: 21px 22px 21px 16px;
box-sizing: border-box;
box-shadow: 0px 0px 11px 2px rgba(147, 147, 147, 0.11);
}
.selected {
width: 20px;
height: 14px;
}
::v-deep .el-collapse-item__header {
height: 40px;
border-bottom: none;
}
::v-deep .el-collapse-item__content {
padding-bottom: 0;
}
::v-deep .el-collapse-item__wrap {
border-bottom: none;
}
</style>