效果如图
点击左侧导航菜单,右侧对应的模块会滚动到顶部位置
滚动右侧区域,模块标题到达顶部,对应左侧菜单会高亮
代码如下
<template>
<div class="wapper-content">
<header>
<strong>菜单资源</strong>
<div class="table-actions">
<el-button type="primary" :disabled="!$permission('base_menu_add')" icon="iconfont el-icon-icon-system-add" @click="clickAddApp">新增</el-button>
</div>
</header>
<section v-loading="pageLoading">
<aside>
<ul>
<li v-for="(item,idx) in menuGroup" :key="idx" :class="idx == index ? 'selected' : ''" @click.stop="changeId(idx)">
<div class="row-li">
{{ item }}
</div>
</li>
</ul>
</aside>
<main
ref="itemList"
:style="
index > 0
? 'box-shadow: 0 -2px 0 rgba(84, 151, 215,.2)'
: ''
"
@scroll="handleScroll($event)"
>
<div ref="rigth">
<div v-for="item in menuList" :key="item.id">
<div class="card">
<strong>{{ item.groupName }}</strong>
<el-row :gutter="16" style="margin:16px 0">
<el-col v-for="menu in item.children" :key="menu.id" :span="6">
<el-card class="card-content" @click.native="toEdit(menu)">
<el-row type="flex" style="margin-bottom:26px">
<svg class="icon svg-icon" aria-hidden="true" style="font-size:42px">
<use :xlink:href="`#${menu.icon}`" />
</svg>
<span class="ml-16">
<strong>{{ menu.name }}</strong>
<article>
{{ menu.description }}
</article>
</span>
</el-row>
<footer>
<el-button class="miniBtn" @click.stop="toEditApp(menu)">
编辑
</el-button>
<el-button class="miniBtn" @click.stop="delApp(menu)">
删除
</el-button>
</footer>
</el-card>
</el-col>
</el-row>
</div>
</div>
</div>
</main>
</section>
<!-- 新增编辑抽屉 -->
<menuDrawer v-if="menuParam.visible" v-bind="menuParam" :visible.sync="menuParam.visible" @success="getMenuList" />
</div>
</template>
<script>
import {
apiBaseMenuNoPage,
apiBaseMenuDelApp
} from '@/api/vone/base/meun'
import menuDrawer from './menuDrawer.vue'
export default {
components: {
menuDrawer
},
data() {
return {
menuGroup: [
'效能管理', '基础应用', '持续交付', '协同管理', '效率工具', '外部应用'
],
menuList: [],
index: 0,
scrollY: 0, // 左侧列表滑动的y轴坐标
scorllEvent: false,
menuParam: { visible: false },
pageLoading: true
}
},
watch: {
scrollY() {
this.initRightBoxHeight()
}
},
mounted() {
this.getMenuList()
// 启动鼠标滚动监听
window.addEventListener(
'mousewheel',
this.setScorllEvent,
true
) ||
window.addEventListener(
'DOMMouseScroll',
this.setScorllEvent,
false
)
},
methods: {
// 新增菜单组
clickAddApp() {
this.menuParam = { visible: true, title: '新增菜单' }
},
toEditApp(item) {
this.menuParam = { visible: true, title: '编辑菜单', id: item.id }
},
changeId(idx) {
this.index = idx
// 点击事件标识非滚动事件
this.scorllEvent = false
this.initRightBoxHeight()
// this.$refs.rigth.scrollTop = this.rightLiTops[idx]
this.$refs['itemList'].scrollTo({
behavior: 'smooth', // 平滑过渡
top: this.rightLiTops[idx]
// block: 'start' // 上边框与视窗顶部平齐。默认值
})
// console.log(this.$refs.rigth, ' this.$refs.rigth')
console.log(this.$refs.rigth.scrollTop, 'this.$refs.rigth.scrollTop2')
},
async getMenuList() {
this.pageLoading = true
const { data, isSuccess, msg } = await apiBaseMenuNoPage({
parentId: 0
})
this.pageLoading = false
if (!isSuccess) {
this.$message.warning(msg)
return
}
const groupMap = {
base: '基础应用',
workflow: '基础应用',
cmdb: '基础应用',
wiki: '效率工具',
si: '效率工具',
project: '协同管理',
producm: '协同管理',
projectm: '协同管理',
reqm_center: '协同管理',
productfit: '协同管理',
testm_test_library: '协同管理',
release: '协同管理',
code: '持续交付',
pipeline: '持续交付',
package: '持续交付',
measure_center: '效能管理',
man_hour: '效能管理',
dashboard: '效能管理'
}
data.forEach(element => {
element.groupName = groupMap[element.code] || '外部应用'
})
const map = {}
data.forEach((item) => {
map[item.groupName] = map[item.groupName] || []
map[item.groupName].push(item)
})
const DATA = Object.keys(map).map((orgName) => {
return {
groupName: orgName,
children: map[orgName]
}
})
this.menuList = DATA
},
setScorllEvent() {
this.scorllEvent = true
},
handleScroll(event) {
// console.log(this.scorllEvent, 'this.scorllEvent ')
console.log(event, 'event')
this.scrollY = event.target.scrollTop
console.log(this.scrollY, 'this.scrollY ')
},
/* 计算每个小盒子高度 */
initRightBoxHeight() {
// console.log(this.scorllEvent, '-------12')
const itemArray = []
let top = 0
itemArray.push(top)
// 获取右边所有子盒子高度集合
const allList = this.$refs.itemList.getElementsByClassName('card')
// console.log(allList, 'allList----')
// allList伪数组转化成真数组
Array.prototype.slice.call(allList).forEach((li) => {
top += li.clientHeight // 获取所有li的每一个高度
itemArray.push(top)
})
// console.log(itemArray, 'itemArray-----')
this.rightLiTops = itemArray
this.rightLiTops.forEach((item, index) => {
if (item < this.scrollY) {
// 当为鼠标滚动时重新赋值
if (this.scorllEvent) {
this.index = index
}
}
})
// console.log(this.index)
},
async delApp(item) {
await this.$confirm(`删除【${item.name}】前请先删除模块下所有的【菜单和功能】`, '提示', {
type: 'warning'
})
const res = await apiBaseMenuDelApp([
item.id
])
if (!res.isSuccess) {
this.$message.warning(res.msg)
return
}
this.$message.success('删除成功')
this.getMenuList()
},
toEdit(item) {
if (!this.$permission('base_menu_config')) return
this.$router.push({
name: 'base_menu_config',
params: {
id: item.id,
path: item.path
}
})
}
}
}
</script>
<style lang="scss" scoped>
@import "~@/styles/variables.scss";
.wapper-content {
min-height: calc(100vh - #{$hasHeader});
border-radius: 4px;
background-color: var(--main-bg-color);
header {
height: 54px;
line-height: 54px;
padding: 0 16px;
border-bottom: 1px solid var(--el-divider);
display: flex;
justify-content: space-between;
.table-actions {
line-height: 54px;
}
}
section {
display: flex;
aside {
width: 216px;
border-right: 1px solid var(--el-divider);
height: calc(100vh - #{$hasHeader} - 54px);
overflow-y: auto;
ul {
.selected {
background-color: var(--tab-bg-color);
color: var(--main-theme-color);
}
li {
.row-li {
line-height: 22px;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
padding: 8px 16px;
cursor: pointer;
span {
a {
display: none;
}
}
a {
color: var(--main-theme-color);
}
a + a {
margin-left: 6px;
}
}
.row-input {
padding: 8px 16px;
}
}
.row-li:hover {
background-color: var(--tab-bg-color);
a {
display: inline-block;
}
}
}
}
main {
position: relative;
padding: 16px;
flex: 1;
height: calc(100vh - #{$hasHeader} - 54px);
overflow-y: scroll;
.el-row + .el-row {
margin-top: 16px;
}
article {
margin: 10px 0;
color: var(--auxiliary-font-color);
line-height: 22px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box; //使用自适应布局
-webkit-line-clamp: 2; //设置超出行数,要设置超出几行显示省略号就把这里改成几
-webkit-box-orient: vertical;
}
.miniBtn {
color: var(--tab-font-color);
border-color: var(--input-border-color);
}
.miniBtn:hover {
color: var(--main-theme-color);
border-color: var(--main-theme-color);
}
.card-content {
height: 142px;
position: relative;
.svg-icon{
width: 50px;
}
.ml-16{
flex: 1;
}
footer {
position: absolute;
bottom: 16px;
right: 16px;
}
}
.el-col + .el-col {
margin-bottom: 16px;
}
.el-card :hover {
cursor: pointer;
}
}
}
}
</style>