<template>
|
<div class="nav-head">
|
<div class="head-label-nav">
|
<span class="label-nav-btn t4" @click="scollByIcon('left')">
|
<ArrowLeft class="head-icon" />
|
</span>
|
<div class="nav-scroll-box" ref="boxWidth">
|
<el-scrollbar class="nav-scroll" ref="tabScrollRef">
|
<ul class="nav-list" ref="container">
|
<template v-if="tabsViewT.length >= 1">
|
<li
|
v-for="(item, index) in tabsViewT"
|
:class="{
|
'nav-item': item.meta.title,
|
active: activeIndex == index,
|
}"
|
:ref="tabsRefs.set"
|
:key="index"
|
@click="changeRouterTab(item)"
|
>
|
<span class="nav-name">{{ item.meta.title }}</span>
|
<span
|
v-if="activeIndex == index"
|
class="nav-refresh"
|
@click.stop="refreshTabView(item)"
|
>
|
<Refresh class="nav-close-icon refresh" />
|
</span>
|
<span
|
v-if="item.name != 'home'"
|
class="nav-close"
|
@click.stop="closeTab(item)"
|
>
|
<CircleCloseFilled class="nav-close-icon" />
|
</span>
|
</li>
|
</template>
|
</ul>
|
<!-- <ul v-if="tabsViewT.length < 1" class="nav-list" ref="container">-->
|
<!-- </ul>-->
|
</el-scrollbar>
|
</div>
|
<span class="label-nav-btn t4" @click="scollByIcon('right')">
|
<ArrowRight class="head-icon" />
|
</span>
|
<span class="label-nav-btn cla" @click="closeAll"> 关闭全部 </span>
|
<!-- <scrolltab>-->
|
<!-- <ul class="nav-list">-->
|
<!-- <li v-for="(item, index) in tabsView" class="nav-item"-->
|
<!-- :class="activeIndex == index ? 'active' : ''" :ref="tabsRefs.set" :key="index"-->
|
<!-- @click="changeRouterTab(item)">-->
|
<!-- <span class="nav-name">{{ item.meta.title }}</span>-->
|
<!-- <span class="nav-close" @click.stop="closeTab(item)">-->
|
<!-- <Close class="nav-close-icon" />-->
|
<!-- </span>-->
|
<!-- </li>-->
|
<!-- </ul>-->
|
<!-- </scrolltab>-->
|
</div>
|
|
<!-- <div class="head-btns">
|
<span class="head-btn refresh-btn" @click="refreshTabView">
|
<Refresh class="head-icon" />
|
</span>
|
<span class="head-btn more-btn">
|
<ArrowDown class="head-icon" />
|
</span>
|
</div> -->
|
</div>
|
</template>
|
|
<script setup lang="ts">
|
import {
|
Close,
|
ArrowLeft,
|
ArrowRight,
|
Refresh,
|
ArrowDown,
|
} from '@element-plus/icons-vue'
|
import { onBeforeRouteUpdate, RouteLocationNormalized } from 'vue-router'
|
import { useCommonInfo } from '@/stores/modules/common' // 状态管理器
|
import { useNavTabs } from '@/stores/modules/navTabs' // 标签导航
|
import { useCommonNonpersistence } from '@/stores/modules/commonNonpersistence' // 缓存
|
import { useTemplateRefsList } from '@vueuse/core'
|
import { useUserInfo } from '@/stores/modules/userInfo'
|
const userStore = useUserInfo()
|
const menuList=userStore.getMenuList
|
const tabsRefs = useTemplateRefsList<HTMLDivElement>()
|
const boxWidth = ref<null | HTMLElement>(null) //外容器
|
const container = ref<null | HTMLElement>(null)
|
const navTabsStore = useNavTabs()
|
const commonNonpersistenceStore = useCommonNonpersistence()
|
const route = useRoute()
|
const router = useRouter()
|
const tabScrollRef = ref()
|
let { tabList, activeTabName } = storeToRefs(useCommonInfo())
|
const { tabsView, activeIndex, activeRoute } = storeToRefs(navTabsStore)
|
|
// 删除掉home的标题
|
tabsView.value.splice(
|
tabsView.value.indexOf(
|
tabsView.value.find((e) => {
|
return e.name === 'home'
|
})
|
),
|
1
|
)
|
const tabsViewT = tabsView
|
|
// console.log("------------------", tabsViewT.value)
|
|
interface State {
|
showLeftIcon: boolean
|
showRightIcon: boolean
|
leftArr: number[]
|
}
|
|
const state: State = reactive({
|
showLeftIcon: false,
|
showRightIcon: false,
|
leftArr: [],
|
})
|
const reload = inject('reload') as any
|
// 刷新当前活跃状态标签对应的页面
|
const refreshTabView = (item: RouteLocationNormalized) => {
|
console.log('刷新活跃状态的页面', item)
|
navTabsStore.updateExcludeViews(item.name)
|
reload()
|
nextTick(() => {
|
navTabsStore.updateExcludeViews('')
|
})
|
}
|
|
// 切换tab导航
|
const changeRouterTab = (menu: RouteLocationNormalized) => {
|
console.log('menu', menu)
|
router.push({
|
path: menu.path,
|
query: menu?.query || {},
|
params: menu?.params || {},
|
})
|
}
|
|
const toLastTab = () => {
|
const lastTab = tabsView.value.slice(-1)[0]
|
if (lastTab) {
|
router.push({
|
path: lastTab.path,
|
query: lastTab.query || {},
|
params: lastTab.params || {},
|
})
|
} else {
|
router.push('/home')
|
}
|
}
|
|
// const toLastTab = () => {
|
// const lastTab = tabsView.value.slice(-1)[0]
|
// console.log("-------", lastTab)
|
// tabsViewT.value.splice(
|
// tabsViewT.value.indexOf(tabsViewT.value.find((e) => {
|
// return e.name === "home";
|
// }
|
// )
|
// ), 1);
|
// if (lastTab) {
|
// router.push({
|
// path: lastTab.path,
|
// query: lastTab.query || {},
|
// params: lastTab.params || {}
|
// })
|
// } else {
|
// router.push('/home')
|
// tabsView.value = []
|
// tabsViewT.value = []
|
// console.log("-=-=--=--", tabsView.value)
|
// console.log("89898988", tabsView.value)
|
//
|
// }
|
// }
|
|
// 移除标签卡
|
const closeTab = (route: RouteLocationNormalized) => {
|
console.log('closeTab route,', route)
|
navTabsStore.closeTab(route)
|
navTabsStore.deleteCachedViews(route.name)
|
const params = {
|
code: route.fullPath,
|
data: {},
|
}
|
commonNonpersistenceStore.removePageCache(params)
|
if (activeRoute.value?.path === route.path) {
|
toLastTab()
|
} else {
|
navTabsStore.setActiveRoute(activeRoute.value!)
|
nextTick(() => {
|
selectNavTab(tabsRefs.value[activeIndex.value])
|
})
|
}
|
}
|
const selectNavTab = (dom: HTMLDivElement) => {}
|
|
const updateTab = (newRoute: RouteLocationNormalized) => {
|
let newRouteCopy:any={...newRoute}
|
// 为了改tab上的名字 和后台同步
|
if(menuList&&menuList.length>0){
|
menuList.forEach((item=>{
|
if(item.url==newRouteCopy.path){
|
newRouteCopy.meta.title=item.name
|
}
|
if(item.children&&item.children.length>0){
|
item.children.forEach((sub:any)=>{
|
if(sub.url==newRouteCopy.path){
|
newRouteCopy.meta.title=sub.name
|
}
|
})
|
}
|
}))
|
}
|
navTabsStore.addTab(newRouteCopy)
|
// 激活当前tab
|
navTabsStore.setActiveRoute(newRouteCopy)
|
nextTick(() => {
|
// 添加tab
|
let bwidth = boxWidth.value?.clientWidth || 0
|
let ulWidth = container.value?.scrollWidth || 0
|
let itemOffsetLeft = tabsRefs.value[activeIndex.value]?.offsetLeft
|
// console.log('外容器的长度 bwidth',bwidth)
|
// console.log('滚动区域的长度scrollWidth',ulWidth)
|
// console.log('元素对于左侧的偏移量',itemOffsetLeft)
|
// console.log('第几个元素',activeIndex.value)
|
if (itemOffsetLeft > bwidth || activeIndex.value >= 14) {
|
container.value?.scrollTo(ulWidth + 200, 0)
|
} else {
|
container.value?.scrollTo(0, 0)
|
}
|
})
|
}
|
|
// 点击图标跳转
|
const scollByIcon = (params: string) => {
|
const { scrollLeft, clientWidth } = container.value!
|
// 左右滚动一屏,保留200px用于连贯显示
|
let stepNum = scrollLeft + (clientWidth - 200)
|
if (params === 'left') {
|
stepNum = scrollLeft - (clientWidth - 200)
|
}
|
// 获取当前应该滚到以哪个开头
|
let index = state.leftArr.findIndex((i) => i > stepNum)
|
index = index > -1 ? index - 1 : state.leftArr.length - 2
|
if (stepNum <= 0 || index < 0) {
|
index = 0
|
}
|
tabScrollRef.value.setScrollLeft(stepNum)
|
container.value!.scrollTo(state.leftArr[index], 0)
|
}
|
onBeforeRouteUpdate(async (to) => {
|
updateTab(to)
|
})
|
|
// 关闭全部tab
|
const closeAll = () => {
|
if (navTabsStore.tabsView.length > 1) {
|
navTabsStore.removeTabs()
|
}
|
router.push('/home')
|
}
|
|
onMounted(() => {
|
updateTab(router.currentRoute.value)
|
})
|
</script>
|
|
<style lang="scss" scoped>
|
.nav-head {
|
width: 100%;
|
display: flex;
|
background-color: #eff3f5;
|
border-top: 1px solid #d4daee;
|
border-bottom: 1px solid #d4daee;
|
line-height: 38px;
|
:deep(.el-scrollbar__view) {
|
height: 100%;
|
}
|
|
.head-label-nav {
|
width: 98.5%;
|
display: flex;
|
|
.label-nav-btn {
|
margin: auto 0px;
|
cursor: pointer;
|
position: relative;
|
}
|
.t4 {
|
top: 4px;
|
padding-left: 5px;
|
}
|
}
|
|
.nav-scroll-box {
|
width: 97%;
|
margin: 0px 2.5px 0px 2.5px;
|
overflow-y: hidden;
|
}
|
|
.nav-scroll {
|
width: 100%;
|
|
:deep(.is-horizontal) {
|
bottom: -10px;
|
}
|
}
|
|
.nav-list {
|
width: 100%;
|
height: 100%;
|
display: flex;
|
justify-content: flex-start;
|
}
|
|
.nav-item {
|
width: auto;
|
height: 100%;
|
margin: auto 5px;
|
display: flex;
|
justify-content: flex-start;
|
padding: 0px 1px;
|
box-sizing: border-box;
|
align-items: center;
|
cursor: pointer;
|
font-size: 15px;
|
border-bottom: 0px;
|
transition: all 0.3s;
|
|
.nav-name {
|
display: block;
|
margin: auto;
|
padding: 0 5px;
|
word-break: keep-all !important;
|
}
|
|
.nav-close,
|
.nav-refresh {
|
margin: auto;
|
display: flex;
|
justify-content: flex-start;
|
|
.nav-close-icon {
|
width: 15px;
|
height: 15px;
|
color: #a1a8c3;
|
}
|
}
|
}
|
|
.active {
|
color: #fff;
|
color: #5867dd;
|
position: relative;
|
&:after {
|
content: '';
|
position: absolute;
|
bottom: 0;
|
height: 2px;
|
background-color: #5867dd;
|
width: 100%;
|
// border-bottom: 2px solid #5867dd;
|
}
|
|
.nav-close,
|
.nav-refresh {
|
.nav-close-icon {
|
color: #5867dd;
|
}
|
}
|
}
|
|
.head-btns {
|
width: 50px;
|
display: flex;
|
justify-content: flex-start;
|
|
.head-btn {
|
display: flex;
|
width: 30px;
|
height: 30px;
|
margin: auto;
|
padding: 5px;
|
justify-content: center;
|
align-items: center;
|
cursor: pointer;
|
}
|
}
|
|
.head-icon {
|
width: 20px;
|
height: 20px;
|
color: #151e4b;
|
}
|
}
|
|
.cla {
|
font-size: 15px;
|
width: 80px;
|
color: #555;
|
position: relative;
|
left: 10px;
|
padding-left: 10px;
|
// top: 0px !important;
|
cursor: pointer;
|
|
&:hover {
|
color: #007cee;
|
}
|
|
&::before {
|
content: '';
|
position: absolute;
|
width: 1px;
|
height: 20px;
|
left: -5px;
|
top: 9px;
|
background-color: #d4daee;
|
}
|
}
|
</style>
|