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
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>
|