pxb 1 tydzień temu
rodzic
commit
8744ce8ad9
2 zmienionych plików z 135 dodań i 47 usunięć
  1. 124 36
      src/components/Breadcrumb/index.vue
  2. 11 11
      src/layout/components/Navbar.vue

+ 124 - 36
src/components/Breadcrumb/index.vue

@@ -1,24 +1,25 @@
 <template>
-  <!--  <el-breadcrumb class="app-breadcrumb" separator="/">-->
-  <!--    <transition-group name="breadcrumb">-->
-  <!--      <el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path">-->
-  <!--        <span v-if="item.redirect==='noRedirect'||index==levelList.length-1" class="no-redirect">{{ item.meta.title }}</span>-->
-  <!--        <a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>-->
-  <!--      </el-breadcrumb-item>-->
-  <!--    </transition-group>-->
-  <!--  </el-breadcrumb>-->
-  <div>
-    <el-tag
-      @click="toPath(tag)"
-      @close="close(tag)"
-      style="margin-top: 20px;margin-right: 10px;cursor: pointer"
-      v-for="tag in keepList"
-      :key="tag.path"
-      closable
-      :type="activeMenu(tag)"
-    >
-      {{ tag.name }}
-    </el-tag>
+  <div class="tab-history">
+    <!-- 左翻页按钮(不可用时隐藏) -->
+    <button v-if="canScrollLeft" class="tab-nav-btn" @click="scrollBy(-1)">«</button>
+
+    <!-- 标签滚动容器 -->
+    <div ref="tabScroll" class="tab-scroll" @scroll="handleScroll">
+      <el-tag
+        class="tab-tag"
+        @click="toPath(tag)"
+        @close="close(tag)"
+        v-for="tag in keepList"
+        :key="tag.path"
+        closable
+        :type="activeMenu(tag)"
+      >
+        {{ tag.name }}
+      </el-tag>
+    </div>
+
+    <!-- 右翻页按钮(不可用时隐藏) -->
+    <button v-if="canScrollRight" class="tab-nav-btn" @click="scrollBy(1)">»</button>
   </div>
 </template>
 
@@ -27,7 +28,9 @@
 export default {
   data() {
     return {
-      levelList: null
+      levelList: null,
+      canScrollLeft: false,
+      canScrollRight: false
     }
   },
   computed: {
@@ -43,24 +46,39 @@ export default {
     }
 
   },
+  mounted() {
+    this.updateNavState()
+    this.$nextTick(() => {
+      // 打开时自动滚动到最新(最右侧)标签
+      this.scrollToEnd()
+    })
+    window.addEventListener('resize', this.updateNavState)
+  },
+  beforeDestroy() {
+    window.removeEventListener('resize', this.updateNavState)
+  },
   watch: {
-    // 监听计算属性的变化
+    // 标签变化后:若新增标签则自动滚动到最右,并更新翻页按钮状态
     keepList: {
       handler(newVal, oldVal) {
-        if (newVal && newVal.length >= 12) {
-          this.$store.commit('user/REMOVE_TAB_BY_PATH', newVal[0].path)
-        }
+        const isNewTab = !oldVal || newVal.length > oldVal.length
+        // 新增标签时自动滚动到最右(最新标签)
+        if (!isNewTab) return
+        // 双重 nextTick:确保新标签完全渲染后再滚动,避免 scrollWidth 未更新导致滚不到最右
+        this.$nextTick(() => {
+          this.$nextTick(() => {
+            this.scrollToEnd()
+            // 滚动可能不到位,再补偿一次确保到最右
+            setTimeout(this.scrollToEnd, 100)
+          })
+        })
       },
       deep: true,
       immediate: true
     }
   },
-  created() {
-    // this.getBreadcrumb()
-  },
   methods: {
     activeMenu(tag) {
-      console.log(this.$route, tag, 'this.$route.name')
       return this.$route.name === tag.path ? 'danger' : ''
     },
     close(tag) {
@@ -74,21 +92,91 @@ export default {
       this.$router.push({
         name: tag.path
       })
+    },
+    // 更新左右翻页按钮可用状态
+    updateNavState() {
+      const el = this.$refs.tabScroll
+      if (!el) return
+      this.canScrollLeft = el.scrollLeft > 0
+      this.canScrollRight = el.scrollLeft + el.clientWidth < el.scrollWidth - 1
+    },
+    // 滚动到最右(最新标签),并更新按钮状态
+    scrollToEnd() {
+      const el = this.$refs.tabScroll
+      if (!el) return
+      el.scrollLeft = el.scrollWidth
+      this.updateNavState()
+    },
+    // 处理滚动事件
+    handleScroll() {
+      this.updateNavState()
+    },
+    // 翻页:左右都逐步滚动约一个标签宽度(即时滚动,避免 smooth 被打断)
+    scrollBy(direction) {
+      const el = this.$refs.tabScroll
+      if (!el) return
+      const step = 140 // 约一个标签的宽度
+      const maxScroll = el.scrollWidth - el.clientWidth
+      const target = Math.max(0, Math.min(el.scrollLeft + direction * step, maxScroll))
+      el.scrollLeft = target
+      this.updateNavState()
     }
   }
 }
 </script>
 
 <style lang="scss" scoped>
-.app-breadcrumb.el-breadcrumb {
-  display: inline-block;
+.tab-history {
+  display: flex;
+  align-items: center;
+  height: 100%;
+  width: 100%;
+  padding: 0 4px;
+  box-sizing: border-box;
+}
+
+.tab-nav-btn {
+  flex-shrink: 0;
+  width: 24px;
+  height: 24px;
+  margin: 0 4px;
+  border: 1px solid rgba(255, 255, 255, 0.4);
+  border-radius: 4px;
+  background: transparent;
+  color: #fff;
   font-size: 14px;
-  line-height: 72px;
-  margin-left: 8px;
+  cursor: pointer;
+  outline: none;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 0;
+
+  &:hover {
+    background: rgba(255, 255, 255, 0.2);
+  }
+}
+
+.tab-scroll {
+  flex: 1;
+  overflow-x: auto;
+  white-space: nowrap;
+  height: 100%;
+  box-sizing: border-box;
+  display: flex;
+  align-items: center;
+  min-width: 0;
+
+  /* 隐藏横向滚动条(保留滚动能力) */
+  &::-webkit-scrollbar {
+    height: 0;
+  }
+  scrollbar-width: none;
 
-  .no-redirect {
-    color: #97a8be;
-    cursor: text;
+  .tab-tag {
+    margin-right: 10px;
+    cursor: pointer;
+    flex-shrink: 0;
   }
 }
 </style>

+ 11 - 11
src/layout/components/Navbar.vue

@@ -1,12 +1,12 @@
 <template>
   <div class="navbar">
     <div v-show="sidebar.opened" class="theTitle">后台管理</div>
-    <hamburger :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
+    <!-- <hamburger :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" /> -->
     <breadcrumb class="breadcrumb-container" />
     <div class="right-menu">
       <div style="display: flex;align-items: center;margin-right: 25px">
 
-        <div style="display: flex; align-items: center; margin-right: 15px;margin-top: 6px">
+        <div style="display: flex; align-items: center; margin-right: 15px">
           <i class="el-icon-bell" style="margin-right: 5px; font-size: 16px; color: #fff;" />
           <el-switch v-model="isSoundOn" active-color="#13ce66" @change="handleSoundChange" />
         </div>
@@ -59,7 +59,7 @@
               </el-badge>
             </div>
           </div>
-          <div slot="reference" style="cursor: pointer; display: flex; align-items: center;margin-top: 6px">
+          <div slot="reference" style="cursor: pointer; display: flex; align-items: center">
             <el-badge :value="totalPending" :max="99" :hidden="totalPending <= 0"
               style="line-height: 1; margin-right: 5px;">
               <span style="font-size: 14px;">待处理 <i class="el-icon-arrow-down" /></span>
@@ -239,31 +239,33 @@ export default {
 <style lang="scss" scoped>
 .navbar {
   height: 60px;
-  margin-top: -10px;
   overflow: hidden;
   position: relative;
   background: #2B5198;
   box-shadow: 0 1px 4px rgba(0, 21, 41, .08);
   color: #fff;
+  display: flex;
+  align-items: center;
 
   .hamburger-container {
     line-height: 72px;
     height: 100%;
-    float: left;
     cursor: pointer;
     transition: background .3s;
     -webkit-tap-highlight-color: transparent;
   }
 
   .breadcrumb-container {
-    float: left;
+    flex: 1;
+    min-width: 0;
+    height: 100%;
   }
 
   .right-menu {
-    float: right;
     height: 100%;
-    line-height: 80px;
     display: flex;
+    align-items: center;
+    flex-shrink: 0;
 
     &:focus {
       outline: none;
@@ -289,7 +291,6 @@ export default {
     .online-stats-pill {
       display: flex;
       align-items: center;
-      margin-top: 6px;
       margin-right: 15px;
       line-height: 1;
       font-size: 13px;
@@ -322,7 +323,6 @@ export default {
       margin-right: 30px;
 
       .avatar-wrapper {
-        margin-top: 5px;
         position: relative;
 
         .user-avatar {
@@ -336,7 +336,7 @@ export default {
           cursor: pointer;
           position: absolute;
           right: -20px;
-          top: 25px;
+          top: 20px;
           font-size: 12px;
         }
       }