Browse Source

新增: close和refresh针对路由操作,closeTab和refreshTab针对页签id操作

zhaihaoyi 6 years ago
parent
commit
04418efedc

+ 1 - 1
src/lib/RouterTab/components/RouterAlive.js

@@ -1,7 +1,7 @@
 import { emptyObj, getAliveKey, getFirstComponentChild, isAlikeRoute, isSameComponentRoute } from '../util'
 
 export default {
-  name: 'router-alive',
+  name: 'RouterAlive',
   props: {
     // 缓存key,如果为函数,则参数为route
     aliveKey: {

+ 62 - 10
src/lib/RouterTab/components/RouterTab.js

@@ -1,10 +1,10 @@
 import Vue from 'vue'
 import RouterAlive from './RouterAlive'
 import langs from '../lang'
-import { emptyObj, emptyArray, scrollTo, debounce, promiseQueue, getAliveKey, isAlikeRoute } from '../util'
+import { emptyObj, emptyArray, logPrefix, scrollTo, debounce, promiseQueue, getAliveKey, isAlikeRoute, getPathWithoutHash } from '../util'
 
 export default {
-  name: 'router-tab',
+  name: 'RouterTab',
   components: { RouterAlive },
   props: {
     // 缓存key,如果为函数,则参数为route
@@ -205,7 +205,7 @@ export default {
       let ids = {}
 
       this.items = tabs.map((item, index) => {
-        let { to, closable } = typeof item === 'string'
+        let { to, closable, title, tips } = typeof item === 'string'
           ? { to: item }
           : (item || emptyObj)
         let route = to && $router.match(to)
@@ -216,7 +216,12 @@ export default {
 
           // 根据id去重
           if (!ids[id]) {
-            return (ids[id] = Object.assign(tab, { closable: closable !== false }))
+            // 初始 tab 数据
+            if (title) tab.title = title
+            if (tips) tab.tips = tips
+            tab.closable = closable !== false
+
+            return (ids[id] = tab)
           }
         }
       }).filter(item => !!item)
@@ -243,6 +248,25 @@ export default {
       }
     },
 
+    // 从路由地址获取 AliveKey
+    getTabIdByLocation (location, fullMatch = true) {
+      if (!location) return
+
+      let $route = this.$router.match(location)
+
+      // 路由地址精确匹配页签
+      if (fullMatch) {
+        let matchPath = getPathWithoutHash($route)
+        let matchTab = this.items.find(({ to }) => to.split('#')[0] === matchPath)
+
+        if (matchTab) {
+          return matchTab.id
+        }
+      } else {
+        return this.getAliveKey($route)
+      }
+    },
+
     // 从route中获取tab数据
     getRouteTab (route) {
       let id = this.getAliveKey(route)
@@ -275,6 +299,10 @@ export default {
       let $alive = this.$refs.routerAlive
       const idx = items.findIndex(item => item.id === id)
 
+      if (items.length === 1) {
+        return Promise.reject(new Error(this.lang.msg.keepOneTab))
+      }
+
       return this.pageLeavePromise(id, 'close').then(function () {
         // 承诺关闭后移除页签和缓存
         $alive.remove(id)
@@ -282,8 +310,20 @@ export default {
       }).catch(e => {})
     },
 
-    // 关闭页签
-    close (id = this.activedTab) {
+    // 通过路由地址关闭页签
+    close (location, fullMatch = true) {
+      if (location) {
+        let id = this.getTabIdByLocation(location, fullMatch)
+        if (id) {
+          this.closeTab(id)
+        }
+      } else {
+        this.closeTab()
+      }
+    },
+
+    // 通过页签id关闭页签
+    closeTab (id = this.activedTab) {
       let { activedTab, items, $router } = this
       const idx = items.findIndex(item => item.id === id)
 
@@ -293,7 +333,7 @@ export default {
           let nextTab = items[idx] || items[idx - 1]
           $router.replace(nextTab.to)
         }
-      })
+      }).catch(e => console.warn(logPrefix, e.message))
     },
 
     // 关闭多个页签
@@ -312,11 +352,23 @@ export default {
       })
     },
 
-    // 刷新指定页签
-    refresh (id = this.activedTab) {
+    // 通过路由地址刷新页签
+    refresh (location, fullMatch = true) {
+      if (location) {
+        let id = this.getTabIdByLocation(location, fullMatch)
+        if (id) {
+          this.refreshTab(id)
+        }
+      } else {
+        this.refreshTab()
+      }
+    },
+
+    // 通过页签id刷新页签
+    refreshTab (id = this.activedTab) {
       this.pageLeavePromise(id, 'refresh').then(() => {
         this.$refs.routerAlive.clear(id)
-        this.reloadRouter()
+        if (id === this.activedTab) this.reloadRouter()
       })
     },
 

+ 3 - 3
src/lib/RouterTab/components/RouterTab.vue

@@ -25,7 +25,7 @@
             }">
               <i v-if="icon" class="tab-icon" :class="icon"></i>
               <span class="tab-title">{{title || lang.tab.untitled}}</span>
-              <i class="tab-close" v-if="closable !== false && items.length > 1" :title="lang.contextmenu.close" @click.prevent="close(id)"></i>
+              <i class="tab-close" v-if="closable !== false && items.length > 1" :title="lang.contextmenu.close" @click.prevent="closeTab(id)"></i>
             </slot>
           </router-link>
         </transition-group>
@@ -52,7 +52,7 @@
     <!-- 右键菜单 -->
     <transition name="router-tab-zoom-lt">
       <div class="router-tab-contextmenu" :style="`left: ${contextmenu.left}px; top: ${contextmenu.top}px;`" v-if="contextmenu.id">
-        <a class="contextmenu-item" :disabled="!isContextTabActived" @click="isContextTabActived && refresh(contextmenu.id)">
+        <a class="contextmenu-item" :disabled="!isContextTabActived" @click="isContextTabActived && refreshTab(contextmenu.id)">
           {{lang.contextmenu.refresh}}
         </a>
 
@@ -60,7 +60,7 @@
           {{lang.contextmenu.refreshAll}}
         </a>
 
-        <a class="contextmenu-item" :disabled="!isContextTabCanBeClosed" @click="isContextTabCanBeClosed && close(contextmenu.id)">
+        <a class="contextmenu-item" :disabled="!isContextTabCanBeClosed" @click="isContextTabCanBeClosed && closeTab(contextmenu.id)">
           {{lang.contextmenu.close}}
         </a>
 

+ 3 - 0
src/lib/RouterTab/lang/en.js

@@ -9,5 +9,8 @@ export default {
     closeLefts: 'Close to the Left',
     closeRights: 'Close to the Right',
     closeOthers: 'Close Others'
+  },
+  msg: {
+    keepOneTab: 'Keep at least 1 tab'
   }
 }

+ 3 - 0
src/lib/RouterTab/lang/zh-CN.js

@@ -9,5 +9,8 @@ export default {
     closeLefts: '关闭左侧',
     closeRights: '关闭右侧',
     closeOthers: '关闭其他'
+  },
+  msg: {
+    keepOneTab: '至少应保留1个页签'
   }
 }

+ 1 - 1
src/lib/RouterTab/mixins/RouterPage.js

@@ -36,7 +36,7 @@ export default {
     // 热加载后Ctor.cid改变
     if (this._ctorId && this._ctorId !== ctorId) {
       this.$destroy()
-      $routerTab.refresh()
+      $routerTab.refreshTab()
     }
 
     this._ctorId = ctorId

+ 1 - 0
src/lib/RouterTab/scss/RouterTab.scss

@@ -57,6 +57,7 @@ $color-primary: #409eff;
     color: $color;
     line-height: $h;
     font-size: 13px;
+    background-color: #fff;
     border: 1px solid $borderColor;
     border-bottom: none;
     cursor: pointer;

+ 1 - 0
src/lib/RouterTab/util.js

@@ -1,6 +1,7 @@
 // 空对象和数组
 export const emptyObj = Object.create(null)
 export const emptyArray = []
+export const logPrefix = '[vue-router-tab]:'
 
 // 是否定义
 export function isDef (v) {