# 两种导航实现方式

# 1.定位方式显示

效果

@ 系统管理>用户管理>新增用户


  <el-main class="main-container">
    <!-- 导航 -->
    <div class="nav-icon">
      <i class="el-icon-location-information" />
    </div>
    <div class="breadcrunb-box">
      <el-breadcrumb separator-class="el-icon-arrow-right">
        <el-breadcrumb-item v-for="(itme, index) in breadcrumb" :key="index">{{ itme }}</el-breadcrumb-item>
      </el-breadcrumb>
    </div>
    <app-main class="app-main" />
  </el-main>


<script>
import { Navbar, Sidebar, AppMain, Footer } from './components'
import { mapGetters } from 'vuex'

export default {
  name: 'Layout',
  components: { Navbar, Sidebar, AppMain, 'footer-component': Footer },
  data() {
    return {
      breadcrumb: ['首页']
    }
  },
  computed: {
    ...mapGetters(['menu_tree', 'user_info'])
  },
  watch: {
    $route(v) {
      this.setBreadcrumb(this.menu_tree, v.path)
    }
  },
  mounted() {
    const menuTree = this.$store.getters.menu_tree
    const uri = this.$route.path
    this.setBreadcrumb(menuTree, uri)
  },
  methods: {
    setBreadcrumb(tree, uri) {
      const breadcrumb_copy = [...this.breadcrumb]
      this.breadcrumb = []
      if (uri === '/' || uri === '/home') {
        this.breadcrumb.push('首页')
        return
      }
      try {
        this.getTreeNode(tree, uri)
      } catch (e) { return }
      if (this.breadcrumb.length === 0) {
        this.breadcrumb = breadcrumb_copy
      }
    },
    getTreeNode(tree, uri) {
      tree.forEach(element => {
        this.breadcrumb.push(element.name)
        if (uri === element.uri) {
          throw element
        }
        const children = element.children
        if (children && children.length > 0) {
          this.getTreeNode(children, uri)
        }
        this.breadcrumb.pop()
      })
    }
  }
}
</script>

# 2.tab切换方式显示(带有组件缓存)

要求

  • 1.路由表深度最多两级
  • 2.AppMain.vue 开启 keep-alive
  • 3.规范每一个 views 组件 name 的值 且唯一 xxxxPage

<template>
  <div class="app-main">
    <el-scrollbar wrap-class="scrollbar-wrapper  scrollbar-wrapper-min-width">
      <transition name="fade" mode="out-in">
        <keep-alive :include="keep_alives">
          <router-view :key="key" />
        </keep-alive>
      </transition>
    </el-scrollbar>
  </div>
</template>

<template>
  <div class="tags-view">
    <div class="div-tabs">
      <el-tabs
        v-model="tabValue"
        type="card"
        closable
        @tab-click="handleTabsClick"
        @tab-remove="handleCloseClick"
      >
        <el-tab-pane v-for="item in tabs" :key="item.path" :label="item.name" :name="item.path" />
      </el-tabs>
    </div>

    <el-dropdown v-show="tabs.length > 1" class="dropdown-close" @command="batchCloseTabs">
      <span class="el-dropdown-link">
        <i class="el-icon-s-fold btn-close" />
      </span>
      <el-dropdown-menu slot="dropdown">
        <el-dropdown-item command="now">关闭当前</el-dropdown-item>
        <el-dropdown-item v-show="tabs.length > 2" command="other">关闭其他</el-dropdown-item>
        <el-dropdown-item v-show="tabs.length > 2" command="all">关闭所有</el-dropdown-item>
      </el-dropdown-menu>
    </el-dropdown>
  </div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
  name: 'TabsView',
  data() {
    return {
      tabValue: '',
      defTabItem: {
        name: '首页',
        path: '/home'
      },
      tabs: []
    }
  },
  computed: {
    ...mapGetters(['menu_list'])
  },
  watch: {
    $route(v) {
      const isExits = this.isExits(v.path)
      if (isExits) {
        this.tabValue = v.path
      } else {
        this.addTabs(v)
        this.addKeepAlives(v)
      }
    }
  },
  mounted() {
    const { name, path } = this.$route
    const route = { name, path }

    // 设置初始值
    this.tabs.push(this.defTabItem)
    this.tabValue = route.path
    const isHave = this.tabs.find(item => {
      return item.path === route.path
    })
    console.log(this.$route)
    if (!isHave) {
      // 直接访问路径的时候
      this.tabs.push(route)
    }
  },
  destroyed() {
    this.tabs.forEach(item => {
      this.removeKeepAlives(item.path)
    })
  },
  methods: {
    handleTabsClick(tab) {
      this.$router.push(tab.name)
    },
    handleCloseClick(targetPath) {
      const len = this.tabs.length
      const defTabItemPath = this.defTabItem.path
      if (targetPath === defTabItemPath) return // 保留首页
      for (var i = 0; i < len; i++) {
        if (this.tabs[i].path === targetPath) {
          var nextTab = this.tabs[i + 1] || this.tabs[i - 1]
          if (nextTab) {
            this.tabValue = nextTab.path
          }
        }
      }
      this.tabs = this.tabs.filter(tab => tab.path !== targetPath)
      this.removeKeepAlives(targetPath)
      this.$router.push(nextTab.path)
    },
    addTabs({ name, path, meta }) {
      const defTabItemPath = this.defTabItem.path
      // 不新开tab
      if (meta.isTab !== undefined && !meta.isTab) return
      if (path === defTabItemPath) return
      const menu = this.menu_list.find(item => {
        return item.uri === path
      })

      // 刷新的时候,调用菜单接口, 所以 vuex 可能没有值
      if (menu) {
        name = menu.name
      }
      this.tabs.push({ name, path })
      this.tabValue = path
    },
    addKeepAlives({ path, meta, matched }) {
      // 不缓存
      if (meta.keepAlive !== undefined && !meta.keepAlive) {
        return
      }
      const targetItem = matched.find(item => {
        return item.path === path
      })
      const componentName = targetItem.components.default.name
      if (componentName) {
        this.$store.commit('menu/PUSH_KEEP_ALIVE', { key: path, value: componentName })
      }
    },
    removeKeepAlives(path) {
      this.$store.commit('menu/RMEOVE_KEEP_ALIVE', path)
    },
    batchCloseTabs: function (command) {
      switch (command) {
        case 'now':
          this.handleCloseClick(this.tabValue)
          break
        case 'other':
          this.removeOtherTabs()
          break
        case 'all':
          this.homeTab()
          break
        default:
          break
      }
    },
    removeOtherTabs: function () {
      this.tabs.forEach(item => {
        const path = item.path
        if (this.tabValue !== item.path) {
          this.removeKeepAlives(path)
        }
      })

      this.tabs = this.tabs
        .filter(tab => tab.path === this.tabValue | tab.path === this.defTabItem.path)
    },
    homeTab: function () {
      const defTabItemPath = this.defTabItem.path
      this.tabs.forEach(item => {
        this.removeKeepAlives(item.path)
      })
      this.tabs.length = 0
      this.tabs.push(this.defTabItem)
      this.tabValue = this.defTabItem.path
      this.$router.push(defTabItemPath)
    },
    isExits: function (path) {
      var len = this.tabs.length
      for (var i = 0; i < len; ++i) {
        if (this.tabs[i].path === path) return true
      }
      return false
    }
  }
}
</script>
<style scoped>
.tags-view >>> .el-icon-arrow-down:before {
  color: #5c8df1;
}
.tags-view >>> .el-tabs__item {
  height: 33px;
  line-height: 33px;
  font-size: 13px;
  border-color: ivory;
  border-top-left-radius: 7px;
  border-top-right-radius: 7px;
}
.tags-view >>> .el-tabs__nav-prev {
  border-top-left-radius: 7px;
  background-color: rgba(160, 225, 251, 0.98);
  line-height: 38px;
  font-size: 16px;
  z-index: 3;
}
.tags-view >>> .el-tabs__nav-next {
  border-top-right-radius: 7px;
  background-color: rgba(160, 225, 251, 0.98);
  line-height: 38px;
  font-size: 16px;
  z-index: 3;
}
.tags-view >>> .el-tabs__nav-wrap.is-scrollable {
  padding: 0;
}
.tags-view >>> .el-tabs--card > .el-tabs__header .el-tabs__item.is-active {
  border-bottom-color: rgba(240, 255, 255, 0.6);
}
.tags-view >>> .el-tabs__item.is-active {
  color: #1890ff;
  background-color: rgba(240, 255, 255, 0.6);
}
</style>
<style lang="scss" scoped>
.tags-view {
  height: 35px;
  border-top-right-radius: inherit;
  padding: 1px 0 0 1px;
  border-bottom: 1px solid #dfe4ed;
  background-color: rgba(64, 184, 255, 0.2);

  .div-tabs {
    position: absolute;
    float: left;
    width: calc(100vw - 300px);
  }
  .dropdown-close {
    cursor: pointer;
    float: right;
  }
  .btn-close {
    font-size: 21px;
    height: 20px;
    margin: 7px 2px;
    color: #5cb6f1;
  }
}
</style>
上次更新时间: 2019-12-1 12:07:38 PM