数据可视化大屏项目开发中,如果菜单太多的话,我们就需要滚动显示。
这里我们要实现菜单可以鼠标拖动滚动,左右箭头点击滚动,点击菜单对应的菜单居中,如果左侧或者右侧没有多余的菜单了则不再滚动。
动态效果
使用到的插件
"@better-scroll/core": "^2.5.1",
实例代码
/**
* @Author: 858834013@qq.com
* @Name: menuList
* @Date: 2024年02月19日
* @Desc: 自动居中的滚动菜单
*/
<template>
<div class="menuList">
<div class="menuListLeft" @click="scrollLeft">
</div>
<div class="tabsBody horizontal-scrollbar-container">
<div class="tabs scroll-wrapper" ref="scroll">
<div class="scroll-content" ref="scroll2">
<div class="newTabs">
<div class="tabItem" @click="scrollToCenter(index)" ref="scrollItem" v-for="(item,index) in list">
<router-link
:key="index"
:to="item.link"
class="tab"
:class="{active: $route.path === item.link}">
<span>{{ item.title }}</span>
</router-link>
</div>
</div>
</div>
</div>
</div>
<div class="menuListRight" @click="scrollRight">
</div>
</div>
</template>
<script>
import BScroll from '@better-scroll/core'
export default {
name: "menuList",
data() {
return {
list: [{
title: '总览',
id: 0,
link: '/home'
}, {
title: '办理建筑许可',
id: 1,
link: '/ProcessBuildingPermit'
}, {
title: '劳动力市场监控',
id: 2,
link: '/LaborMarketMonitoring'
}, {
title: '获得信贷',
id: 3,
link: '/ObtainCredit'
}, {
title: '办理破产',
id: 4,
link: '/FileBankruptcy'
}, {
title: '执行合同',
id: 5,
link: '/EnforceContract'
}, {
title: '政府采购',
id: 6,
link: '/GovernmentProcurement'
}, {
title: '纳税分析',
id: 7,
link: '/TaxAnalysis'
}, {
title: '保护中小投资者',
id: 8,
link: '/ProtectingSmallInvestors'
}, {
title: '登记财产',
id: 9,
link: '/RegisterProperty'
}, {
title: '跨境贸易',
id: 9,
link: '/CrossBorderTrade'
}, {
title: '获得电力',
id: 9,
link: '/AcquireElectricity'
}, {
title: '企业开办',
id: 9,
link: '/StartEnterprise'
}],
}
},
mounted() {
var that = this;
that.$nextTick(() => {
that.scrollInit();
setTimeout(() => {
const currentPath = this.$route.path;
console.log(currentPath)
// 查找当前路由在list中的下标
const currentIndex = this.list.findIndex(item => item.link === currentPath);
// 如果找到了对应的下标,触发scrollToCenter方法
if (currentIndex !== -1) {
this.scrollToCenter(currentIndex);
}
}, 1000)
// 获取当前路由路径
});
},
methods: {
scrollLeft() {
this.scroll.scrollTo(this.scroll.x + 200, 0, 500);
},
scrollRight() {
this.scroll.scrollTo(this.scroll.x - 200, 0, 500);
},
scrollToCenter(index) {
this.$nextTick(() => {
// 确保DOM已更新
const scrollItems = this.$refs.scrollItem;
if (scrollItems && scrollItems.length > index) {
const targetElement = scrollItems[index];
const scrollContainerRect = this.$refs.scroll.getBoundingClientRect();
const targetElementRect = targetElement.getBoundingClientRect();
// 计算目标元素中心相对于滚动容器中心的偏移
let offsetX = targetElementRect.left + targetElementRect.width / 2 - scrollContainerRect.left - scrollContainerRect.width / 2;
// 计算滚动的目标位置
let targetX = this.scroll.x - offsetX;
// 获取滚动容器的最大滚动宽度
const maxScrollX = this.scroll.maxScrollX;
// 确保目标位置不超出滚动容器的边界
targetX = Math.max(targetX, maxScrollX);
targetX = Math.min(targetX, 0);
// 使用BetterScroll的scrollTo方法滚动到目标位置
this.scroll.scrollTo(targetX, 0, 500);
}
});
},
scrollInit() {
var that = this
this.scroll = new BScroll(this.$refs.scroll, {
scrollX: true,
scrollY: false,
click: true,
bounce: true, // 禁用回弹效果
probeType: 1,
scrollbar: {
fade: false,
interactive: false,
scrollbarTrackClickable: false,
scrollbarTrackOffsetType: 'clickedPoint' // can use 'step'
}
})
this.scroll.on('scrollEnd', (e) => {
console.log('scrollEnd')
this.lastSpot = Math.abs(e.x)
})
this.scroll.on('scrollStart', (e) => {
console.log('scrollStart')
console.log(e)
})
this.scroll.on('scroll', () => {
console.log('scroll')
})
}
}
}
</script>
<style scoped lang="scss">
.menuList {
display: flex;
justify-content: center;
align-items: center;
flex-wrap: nowrap;
flex-direction: row;
position: relative;
height: 100%;
width: calc(100% - 0px);
.tab {
height: calc(100% - 5px);
position: relative;
//width: 178px;
//background: url("./assets/tabbg.png");
//background-size: 100% 100%;
opacity: 1;
display: flex;
cursor: pointer;
justify-content: center;
align-items: center;
flex-wrap: nowrap;
flex-direction: row;
align-content: flex-start;
border-bottom: 2px solid rgba(#ACE5FF, 0);
span {
font-size: 26px;
font-family: YouSheBiaoTiHei;
font-weight: 400;
color: #BBCDE6;
}
}
.tab.active {
opacity: 1;
display: flex;
justify-content: center;
align-items: center;
flex-wrap: nowrap;
flex-direction: row;
align-content: flex-start;
border-bottom: 2px solid #ACE5FF;
span {
font-size: 26px;
font-family: YouSheBiaoTiHei;
font-weight: 400;
color: #BBCDE6;
background: linear-gradient(180deg, #ACE5FF 0%, #FFFFFF 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
}
.menuListLeft {
width: 33px;
background: url("./assets/icon_left.png") no-repeat;
background-size: 100% 100%;
height: 46px;
cursor: pointer;
}
.menuListRight {
width: 33px;
background: url("./assets/icon_right.png") no-repeat;
background-size: 100% 100%;
height: 46px;
cursor: pointer;
}
}
.tabsBody {
width: 100%;
overflow: hidden;
position: relative;
//height: 100%;
height: calc(100% - 10px);
//margin-bottom: 10px;
}
.newTabs {
display: flex;
display: -webkit-flex;
padding: 0;
position: relative;
height: calc(100% - 10px);
}
.tabItem {
position: relative;
height: 100%;
margin-left: 20px;
margin-right: 20px;
}
.tabs {
display: flex;
display: -webkit-flex;
padding: 0;
position: relative;
height: 100%;
.tab {
position: relative;
//width: 200px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
height: 100%;
span {
font-size: 26px;
font-family: YouSheBiaoTiHei;
font-weight: 400;
color: #BBCDE6;
}
}
}
.scroll-content {
display: inline-block;
align-self: center;
position: relative;
height: 100%;
}
</style>
更新
2024年02月21日
如果页面是通过点击菜单进行跳转的菜单会滚动对应的菜单位置,当刷新页面后菜单组件没有滚动到对应的位置,当页面刷新后马上获取路由会回去不到准确的路由,我们延迟1秒再获取然后触发滚动方法。
mounted() {
var that = this;
that.$nextTick(() => {
that.scrollInit();
setTimeout(() => {
const currentPath = this.$route.path;
console.log(currentPath)
// 查找当前路由在list中的下标
const currentIndex = this.list.findIndex(item => item.link === currentPath);
// 如果找到了对应的下标,触发scrollToCenter方法
if (currentIndex !== -1) {
this.scrollToCenter(currentIndex);
}
}, 1000)
// 获取当前路由路径
});
},