根据项目需求,需要对已点击过的路由菜单进行保存,并展示在页面上方,所以需要定义一个公共组件来实现该功能
1.思路
根据element-ui里面的tabs组件,进行设计,符合当前项目tabs组件
搭建页面
html-css部分
<template>
<div class="bread_container" ref="bread_container">
<div class="scroll_btn pre" @click="scrollTab(false)" v-show="hideBtn">
<i class="el-icon-arrow-left"></i>
</div>
<ul ref="scroll_content">
<li
v-for="item in breadList"
:key="item.name"
:class="[defaultActive == item.path ? 'bread_active' : '']"
:aria-selected="defaultActive == item.path"
>
<span @click="selectTab(item)">{{ item.name }}</span>
<i
:class="[!defaultActive == item.path ? 'hideClose' : '']"
class="el-icon-close"
style="margin-left: 10px"
@click="removeTab(item)"
></i>
</li>
</ul>
<div class="scroll_btn next" @click="scrollTab(true)" v-show="hideBtn">
<i class="el-icon-arrow-right"></i>
</div>
</div>
</template>
<style lang="less" scoped>
.bread_container {
width: 100%;
height: 48px;
background: #fff;
box-sizing: border-box;
position: relative;
display: flex;
align-items: last baseline;
padding: 0 20px;
box-sizing: border-box;
overflow: hidden;
.scroll_btn {
height: 100%;
width: 20px;
position: absolute;
top: 50%;
transform: translateY(-50%);
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
background: #fff;
z-index: 20;
box-shadow: 0 0 10px 1px #ececec;
}
.pre {
left: 0;
}
.next {
right: 0;
}
ul {
width: 100%;
white-space: nowrap;
transform: translateX(0);
transition: all .3s linear;
li {
padding: 0 15px;
display: inline-block;
height: 40px;
line-height: 40px;
font-size: 14px;
color: #999999;
cursor: pointer;
box-sizing: border-box;
margin-right: 10px;
min-width: 88px;
text-align: center;
// position: relative;
white-space: nowrap;
&:hover {
color: @theme_Color;
.el-icon-close {
display: inline;
}
}
transition: all 0.3s linear;
}
.bread_active {
color: @theme_Color;
background: #f5f6fa;
border-radius: 10px 10px 0px 0px;
}
.hideClose {
display: none;
}
}
}
</style>
js部分
由于网页刷新之后,保存的数据消失,所以需要用到vuex 和sessionStorage进行持久化存储
用的是 vuex-persistedstate 插件
import Vue from 'vue'
import Vuex from 'vuex'
import modules from './modules/index'
import createPersistedstate from 'vuex-persistedstate'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
},
mutations: {
},
actions: {
},
modules,
plugins:[
createPersistedstate({
storage:window.sessionStorage, // 储存方式
key:'bread', // 键名
paths:['menu'] // 生效的模块
})
]
})
模块内逻辑
// 设置默认选中的路由
const defaultRoute = '/baseData';
export default {
state: {
defaultActive: defaultRoute, // 默认路由
breadList: [] // 存储的数组
},
mutations: {
SET_BREADLIST(state, data) {
state.breadList.push(data) // 添加动作
},
SET_DEFAULTACTIVE(state, data) {
state.defaultActive = data.path // 设置默认选中路由
},
REMOVE_BREADLIST_ITEM(state, data) {
// 查找下标
let index = state.breadList.indexOf(data);
let tabs = state.breadList
// 如果删除的不是选中的tab 只做删除动作
if (data.path !== state.defaultActive) {
state.breadList = tabs.filter(item => {
if (item.name !== data.name) {
return item
}
})
return
}
// 设置下一个为默认选中
let nextActive = tabs[index - 1] || tabs[index + 1]
if (nextActive) {
state.defaultActive = nextActive.path
}
// 设置breadList
state.breadList = tabs.filter(item => {
if (item.name !== data.name) {
return item
}
})
// 如果list为空 重置默认tab
!state.breadList.length && (state.defaultActive = defaultRoute)
}
},
actions: {
},
}
AsideItem.vue文件中
<template>
<div>
<label v-for="item in menuList" :key="item.name">
<el-submenu :index="item.path" v-if="item.children">
<template slot="title">
<i class="el-icon-location"></i>
<span>{{item.name}}</span>
</template>
<el-menu-item-group>
<aside-Item :menuList = "item.children"></aside-Item>
</el-menu-item-group>
</el-submenu>
<el-menu-item v-else :index="item.path" @click="setBreadList(item)">{{ item.name }}</el-menu-item>
</label >
</div>
</template>
<script>
import { mapState } from 'vuex';
export default {
name: "aside-Item",
components: {},
props:{
menuList:{
type:Array,
default:()=>{
return []
}
}
},
data() {
return {};
},
computed:{
...mapState({
breadList:state=>state.menu.breadList // 获取vuex中list列表
})
},
methods:{
// 点击菜单的方法
setBreadList(item){
// 是否已存储
let isHas = this.breadList.find(v=>v.name==item.name)
if (!isHas) {
this.$store.commit('SET_BREADLIST',item) // 添加tab
}
this.$store.commit('SET_DEFAULTACTIVE',item) // 设置选中的tab
}
}
};
</script>
<style lang="less" scoped>
.el-menu-item {
margin: 0 5px;
border-radius: 10px;
}
.el-menu-item.is-active {
background-color: #F7F7FF !important;
}
</style>
<script>
import { mapState } from "vuex";
export default {
name: "",
components: {},
data() {
return {
wd: 0,
hideBtn:false
};
},
computed: {
...mapState({
defaultActive: (state) => state.menu.defaultActive, // 获取vuex中的选中路径
breadList: (state) => state.menu.breadList, // 获取vuex中list列表
}),
},
methods: {
selectTab(item) {
// 设置默认选中
this.$store.commit("SET_DEFAULTACTIVE", item);
},
removeTab(item) {
// 删除tab
this.$store.commit("REMOVE_BREADLIST_ITEM", item);
this.scrollTab(false)
},
// 点击左右按钮 控制滚动距离
scrollTab(flag) {
this.$nextTick(()=>{
let scroll = this.$refs["scroll_content"]; // 滚动容器
let scrollNum = scroll.offsetWidth; // 单次滚动距离
let canScrollWidth = scroll.scrollWidth - scroll.offsetWidth; // 总体可滚动距离
if (flag) {
this.wd +=scrollNum
if (this.wd > canScrollWidth) {
this.wd = canScrollWidth
}
scroll.style.transform = `translateX(${-this.wd}px)`;
}else{
this.wd -= scrollNum
if (this.wd < 0) {
this.wd = 0
}
scroll.style.transform = `translateX(${-this.wd}px)`;
}
})
},
// 控制按钮显示隐藏
hideShowBtn(){
let scroll = this.$refs["scroll_content"];
this.hideBtn = scroll.scrollWidth > scroll.offsetWidth; // 是否显示左右按钮
this.positionTab() // 定位到指定位置
},
// 定位到选中tab栏
positionTab(){
this.$nextTick(()=>{
let scroll = this.$refs["scroll_content"];
let liDom = scroll.querySelectorAll('li');
let left = 0
// 获取选中的tab
for(let i = 0; i<liDom.length; i++){
if (liDom[i].ariaSelected == 'true') {
left = liDom[i].offsetLeft
}
}
let num = Math.ceil(left / scroll.offsetWidth) // 执行次数
let index = 0
while (index <= num) {
index+=1
left < scroll.offsetWidth ? this.scrollTab(false) : this.scrollTab(true) // 定位到已选中的按钮
}
})
}
},
mounted(){
// 重新加载时 执行按钮显示判断
this.hideShowBtn()
},
watch:{
breadList:{
// immediate:true,
handler(){
// 监视宽度变化 添加tab栏时向右滑动
this.scrollTab(true)
// 控制隐藏按钮
this.hideShowBtn()
}
},
defaultActive:{
// 监听选中的路径变化 跳转到指定位置
handler(){
this.positionTab()
}
}
}
};
</script>