123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260 |
- <template>
- <div class="tabs">
- <el-scrollbar ref="scrollbarDom" class="scroll-container tags-view-container">
- <Item v-for="menu in menuList" :key="menu.meta.title" :active="activeMenu === menu.path" :menu="menu"
- @close="delMenu(menu)"/>
- </el-scrollbar>
- <div class="handle">
- <el-dropdown placement="bottom">
- <div class="el-dropdown-link">
- <i class="el-icon-arrow-down el-icon--right"></i>
- </div>
- <template #dropdown>
- <el-dropdown-menu>
- <el-dropdown-item :disabled="currentDisabled" icon="el-icon-circle-close" @click="closeCurrentRoute">
- 关闭当前标签
- </el-dropdown-item>
- <el-dropdown-item :disabled="menuList.length < 3" icon="el-icon-circle-close" @click="closeOtherRoute">
- 关闭其他标签
- </el-dropdown-item>
- <el-dropdown-item :disabled="menuList.length <= 1" icon="el-icon-circle-close" @click="closeAllRoute">
- 关闭所有标签
- </el-dropdown-item>
- </el-dropdown-menu>
- </template>
- </el-dropdown>
- <el-tooltip :content="contentFullScreen ? '退出全屏' : '内容全屏'" class="item" effect="dark" placement="bottom">
- <i class="el-icon-full-screen" @click="onFullscreen"></i>
- </el-tooltip>
- </div>
- </div>
- </template>
- <script name="tabs" setup>
- import Item from './item.vue'
- import {computed, nextTick, ref, watch} from 'vue'
- import {useStore} from 'vuex'
- import {useRoute, useRouter} from 'vue-router'
- import tabsHook from './tabsHook'
- const store = useStore()
- const route = useRoute()
- const router = useRouter()
- const scrollbarDom = ref(null)
- const defaultMenu = {
- path: '/dashboard',
- meta: {title: '首页', hideClose: true},
- }
- const contentFullScreen = computed(() => store.state.app.contentFullScreen)
- const currentDisabled = computed(() => route.path === defaultMenu.path)
- let activeMenu = $ref('')
- let menuList = ref(tabsHook.getItem())
- if (menuList.value.length === 0) {
- // 判断之前有没有调用过
- addMenu(defaultMenu)
- }
- watch(menuList.value, (newVal) => {
- tabsHook.setItem(newVal)
- })
- watch(menuList, (newVal) => {
- tabsHook.setItem(newVal)
- })
- router.afterEach(() => {
- addMenu(route)
- initMenu(route)
- })
- // 全屏
- function onFullscreen() {
- store.commit('app/contentFullScreenChange', !contentFullScreen.value)
- }
- // 关闭当前标签,首页不关闭
- function closeCurrentRoute() {
- if (route.path !== defaultMenu.path) {
- delMenu(route)
- }
- }
- // 关闭除了当前标签之外的所有标签
- function closeOtherRoute() {
- menuList.value = [defaultMenu]
- if (route.path !== defaultMenu.path) {
- addMenu(route)
- }
- setKeepAliveData()
- }
- // 关闭所有的标签,除了首页
- function closeAllRoute() {
- menuList.value = [defaultMenu]
- setKeepAliveData()
- router.push(defaultMenu.path)
- }
- // 添加新的菜单项
- function addMenu(menu) {
- let {path, meta, name} = menu
- if (meta.activeMenu) {
- let a = menuList.value.some((obj) => {
- return obj.path === meta.activeMenu
- })
- if (!a) {
- menuList.value.push({
- path: meta.activeMenu,
- meta: {title: meta.parentName}
- })
- }
- return;
- } else if (meta.hideTabs) {
- return
- }
- let hasMenu = menuList.value.some((obj) => {
- return obj.path === path || obj.path === meta.activeMenu
- })
- if (!hasMenu) {
- menuList.value.push({
- path,
- meta,
- name,
- })
- }
- }
- // 删除菜单项
- function delMenu(menu) {
- if (!menu.meta.hideClose) {
- if (menu.meta.cache && menu.name) {
- store.commit('keepAlive/delKeepAliveComponentsName', menu.name)
- }
- menuList.value.splice(
- menuList.value.findIndex((item) => item.path === menu.path),
- 1
- )
- }
- if (menu.path === activeMenu) {
- router.push(defaultMenu.path)
- }
- }
- // 初始化activeMenu
- function initMenu(menu) {
- if (menu.meta.activeMenu) {
- activeMenu = menu.meta.activeMenu
- } else {
- activeMenu = menu.path
- }
- nextTick(() => {
- setPosition()
- })
- }
- // 设置当前滚动条应该在的位置
- function setPosition() {
- if (scrollbarDom.value) {
- const domBox = {
- scrollbar: scrollbarDom.value.scrollbar.querySelector('.el-scrollbar__wrap '),
- activeDom: scrollbarDom.value.scrollbar.querySelector('.active'),
- activeFather: scrollbarDom.value.scrollbar.querySelector('.el-scrollbar__view'),
- }
- for (let i in domBox) {
- if (!domBox[i]) {
- return
- }
- }
- const domData = {
- scrollbar: domBox.scrollbar.getBoundingClientRect(),
- activeDom: domBox.activeDom.getBoundingClientRect(),
- activeFather: domBox.activeFather.getBoundingClientRect(),
- }
- const num = domData.activeDom.x - domData.activeFather.x + (1 / 2) * domData.activeDom.width - (1 / 2) * domData.scrollbar.width
- domBox.scrollbar.scrollLeft = num
- }
- }
- // 配置需要缓存的数据
- function setKeepAliveData() {
- let keepAliveNames = []
- menuList.value.forEach((menu) => {
- menu.meta && menu.meta.cache && menu.name && keepAliveNames.push(menu.name)
- })
- store.commit('keepAlive/setKeepAliveComponentsName', keepAliveNames)
- }
- // 初始化时调用:1. 新增菜单 2. 初始化activeMenu
- addMenu(route)
- initMenu(route)
- </script>
- <style lang="scss" scoped>
- .tabs {
- display: flex;
- justify-content: space-between;
- align-items: center;
- height: 40px;
- background: var(--system-header-background);
- border-bottom: 1px solid var(--system-header-border-color);
- border-top: 1px solid var(--system-header-border-color);
- box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.1);
- .handle {
- min-width: 95px;
- height: 100%;
- display: flex;
- align-items: center;
- .el-dropdown-link {
- margin-top: 5px;
- border-left: 1px solid var(--system-header-border-color);
- height: 25px;
- width: 40px;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- i {
- color: var(--system-header-text-color);
- }
- }
- }
- .scroll-container {
- white-space: nowrap;
- position: relative;
- overflow: hidden;
- width: 100%;
- :deep {
- .el-scrollbar__bar {
- bottom: 0px;
- }
- .el-scrollbar__wrap {
- height: 49px;
- }
- }
- }
- .tags-view-container {
- height: 34px;
- flex: 1;
- width: 100%;
- display: flex;
- }
- .el-icon-full-screen {
- cursor: pointer;
- &:hover {
- background: rgba(0, 0, 0, 0.025);
- }
- &:focus {
- outline: none;
- }
- }
- </style>
|