Selaa lähdekoodia

feat: 内置 fullPath 页签规则,补充相关文档和Demo

zhaihaoyi 6 vuotta sitten
vanhempi
sitoutus
d1e03f4ddf

+ 0 - 1
README.md

@@ -1,4 +1,3 @@
-
 <p align="center">
   <a href="https://bhuh12.github.io/vue-router-tab/" target="_blank" rel="noopener noreferrer">
     <img width="100" src="public/img/logo.png" alt="vue-router-tab logo">

+ 17 - 17
docs/api.md

@@ -6,24 +6,24 @@
 
 页面组件缓存的 id
 
-- 类型: `string | Function`
+- 类型: `String | Function`
 
-  - 如果类型为 `string` ,则取 `$route[aliveId]` 的值
+  - 如果类型为 `String` ,则可使用内置的缓存规则,`path` (默认) 和 `fullPath`
 
-  - 如果类型为 `Function` ,则取 `aliveId($route)` 返回的字符串。该函数不应返回随机变化的字符串,以免页签无法与缓存的页面对应
+  - 如果类型为 `Function` ,则取 `aliveId(route)` 返回的字符串。该函数传入相同的 `route` 应返回固定的字符串,以免页签无法与缓存的页面对应
 
 - 默认值: `'path'`
   
-  根据 `$route.path` 来缓存页面组件。
+  根据 `route.path` 来缓存页面组件。
 
 
 ### i18n
 
 语言配置
 
-- 类型: `string | Object`
+- 类型: `String | Object`
 
-  - 如果类型为 `string` ,可以设置为内置的语言 `'zh-CN'` (默认) 和 `'en'`
+  - 如果类型为 `String` ,可以设置为内置的语言 `'zh-CN'` (默认) 和 `'en'`
 
   - 如果类型为 `Object` ,可设置自定义的语言
 
@@ -34,9 +34,9 @@
 
 **初始页签数据**,进入页面时默认显示的页签。相同 `aliveId` 的页签只保留第一个
 
-- 类型: `Array <string | Object>`
+- 类型: `Array <String | Object>`
   
-  - tabs子元素类型为 `string` 时,应配置为要打开页面的 `fullPath` ,页签的标题、图标、提示等信息会从对应页面的 `router` 配置中获取
+  - tabs子元素类型为 `String` 时,应配置为要打开页面的 `fullPath` ,页签的标题、图标、提示等信息会从对应页面的 `router` 配置中获取
 
   - tabs子元素类型为 `Object` 时:
     
@@ -64,9 +64,9 @@
 
 **页签过渡效果**,新增和关闭页签时的过渡
 
-- 类型: `string | Object`
+- 类型: `String | Object`
 
-  - 类型为 `string` 时,应配置为 `transition.name`
+  - 类型为 `String` 时,应配置为 `transition.name`
 
   - 类型为 `Object` 时,配置参考: [Vue - transition](https://cn.vuejs.org/v2/api/#transition)
 
@@ -77,7 +77,7 @@
 
 **页面过渡效果**
 
-- 类型: `string | Object`
+- 类型: `String | Object`
   
   同 [`tab-transition`](#tab-transition)
 
@@ -103,7 +103,7 @@
 ### routerTab.close
 
 - **参数**:
-  - `{string | Object} [location]` 路由地址 - [参考文档](https://router.vuejs.org/zh/guide/essentials/navigation.html#router-push-location-oncomplete-onabort)
+  - `{String | Object} [location]` 路由地址 - [参考文档](https://router.vuejs.org/zh/guide/essentials/navigation.html#router-push-location-oncomplete-onabort)
   - `{Boolean} [fullMatch = true]` 是否全匹配(匹配fullPath去除hash部分)
 
 - **说明**:
@@ -114,7 +114,7 @@
 ### routerTab.refresh
 
 - **参数**:
-  - `{string | Object} [location]` 路由地址 - [参考文档](https://router.vuejs.org/zh/guide/essentials/navigation.html#router-push-location-oncomplete-onabort)
+  - `{String | Object} [location]` 路由地址 - [参考文档](https://router.vuejs.org/zh/guide/essentials/navigation.html#router-push-location-oncomplete-onabort)
   - `{Boolean} [fullMatch = true]` 是否全匹配(匹配fullPath去除hash部分)
 
 - **说明**:
@@ -139,7 +139,7 @@
 
 ### meta.title
 
-- 类型: `string`
+- 类型: `String`
 - 默认值: `'新页签'`
 
 页签标题
@@ -147,14 +147,14 @@
 
 ### meta.icon
 
-- 类型: `string`
+- 类型: `String`
 
 页签图标
 
 
 ### meta.tips
 
-- 类型: `string`
+- 类型: `String`
 - 默认值: 默认和页签标题 `meta.title` 保持一致
 
 页签提示
@@ -178,7 +178,7 @@
     - `{Function} resolve` 执行后允许离开页签
     - `{Function} reject` 执行后阻止离开页签
     - `{Object} tab` 页签信息
-    - `{string} type` 离开类型:`close`: '关闭', `refresh`: '刷新', `replace`: '替换'
+    - `{String} type` 离开类型:`close`: '关闭', `refresh`: '刷新', `replace`: '替换'
 
   - **说明**: 页面离开确认。页面组件选项,与 `data`, `methods` 并列
 

+ 15 - 22
docs/guide.md

@@ -243,31 +243,18 @@ this.$routerTab.refreshAll(true)
 
 不同的页签维护着各自的页面缓存,而**页签规则**定义了不同的路由**打开页签的方式**。
 
-### 默认页签规则
 
-`RouterTab` 默认取页面路由的 `$route.path` 作为缓存的 `alive-id`。
+### 内置规则
 
-这意味着,`$route.path` 相同的页面在同一个页签打开,新打开的页面会替换旧的页面,而 `$route.path` 不同的页面则打开独立的页签。
+- `path` (默认规则)
+  - 规则:`route => route.path` 
+  - 说明:相同route.params的路由共用页签
+  - <demo-link href="/default/rule/a/1"/>
 
-::: tip 规则说明:
-  - 同一路由、不同 `$route.params` 的页面,各自打开独立的页签,单独缓存
-
-  - 同一路由、相同 `$route.params` 、不同 `$route.query` 的页面,共用同一个页签,后打开的页面将会替换之前页签内的页面,并且旧的页面缓存也被清除
-
-  - 仅仅 `$route.hash` 不同的页面,共用同一页签和缓存
-:::
-
-
-例如:下面表格的前三个地址的 `$route.path` 都是 **/page/1**,它们打开同一个页签。后三个地址的 `$route.path` 都是 **/page/2**,它们打开时共用另一个页签。
-
-| 地址 | `$route.path` |
-| ---- | ---- |
-| /page/1 | /page/1 |
-| /page/1?query=2 | /page/1 |
-| /page/1#hash1 | /page/1 |
-| /page/2 | /page/2 |
-| /page/2?query=2 | /page/2 |
-| /page/2#hash1 | /page/2 |
+- `fullPath`
+  - 规则:`route => route.fullPath.replace(route.hash, '')` 
+  - 说明:相同route.params和route.query的路由共用页签
+  - <demo-link href="/global-rule/rule/a/1"/>
 
 
 ### 全局页签规则
@@ -286,6 +273,12 @@ this.$routerTab.refreshAll(true)
 
 根据该规则,`page/1` 和 `page/1?query=2`、`page/2`、`page/2?query=2` 这四个地址都是打开**不同**的页签。而 `page/1` 和 `page/1#hash1` 是同一个页签,因为它们忽略 `hash` 后的路径一致。
 
+该规则已经内置在 `RouterTab` 中了,因此,您也可以直接这样使用:
+
+``` html
+<router-tab alive-id="fullPath"/>
+```
+
 
 ### 路由页签规则
 

+ 17 - 0
src/assets/scss/demo.scss

@@ -95,3 +95,20 @@ a:link {
     border-color: $activeColor;
   }
 }
+
+// 表格
+.demo-table {
+  min-width: 300px;
+  border-collapse: collapse;
+
+  th, td {
+    padding: 5px 8px;
+    border: 1px solid #ddd;
+  }
+
+  th {
+    text-align: left;
+    font-weight: 400;
+    background-color: #f7f7f7;
+  }
+}

+ 1 - 19
src/components/PageRouteInfo.vue

@@ -1,5 +1,5 @@
 <template>
-  <table class="route-info">
+  <table class="demo-table">
     <tr>
       <th width="80">
         name
@@ -28,21 +28,3 @@
     </tr>
   </table>
 </template>
-
-<style lang="scss" scoped>
-.route-info {
-  min-width: 300px;
-  border-collapse: collapse;
-
-  th, td {
-    padding: 5px 8px;
-    border: 1px solid #ddd;
-  }
-
-  th {
-    text-align: left;
-    font-weight: 400;
-    background-color: #f7f7f7;
-  }
-}
-</style>

+ 1 - 1
src/components/layout/GlobalRule.vue

@@ -1,5 +1,5 @@
 <template>
   <main class="app-main">
-    <router-tab :alive-id="route => route.fullPath.replace(route.hash, '')" />
+    <router-tab alive-id="fullPath" />
   </main>
 </template>

+ 12 - 0
src/lib/RouterTab/rules.js

@@ -0,0 +1,12 @@
+// 页签规则
+export default {
+  // 地址,例如:"/page/1?type=a#title" 则取 "/page/1"
+  path (route) {
+    return route.path
+  },
+
+  // 完整地址 (忽略hash),例如:"/page/1?type=a#title" 则取 "/page/1?type=a"
+  fullpath (route) {
+    return route.fullPath.replace(route.hash, '')
+  }
+}

+ 13 - 5
src/lib/RouterTab/util.js

@@ -1,3 +1,5 @@
+import rules from './rules'
+
 // 空对象和数组
 export const emptyObj = Object.create(null)
 export const emptyArray = []
@@ -51,13 +53,19 @@ export function getFirstComponentChild (children) {
   }
 }
 
-// 获取缓存key
+// 获取缓存 id
 export function getAliveId (route = this.$route) {
-  let aliveId = (route.meta && route.meta.aliveId) || this.aliveId || 'path'
-  if (typeof aliveId === 'function') {
-    return aliveId.bind(this)(route)
+  let rule = (route.meta && route.meta.aliveId) || this.aliveId
+
+  if (typeof rule === 'string') {
+    rule = rules[rule.toLowerCase()]
   }
-  return route[aliveId]
+
+  if (typeof rule !== 'function') {
+    rule = rules.path
+  }
+
+  return rule.bind(this)(route)
 }
 
 /* 路由方法 */

+ 46 - 38
src/views/Rule.vue

@@ -1,31 +1,25 @@
 <template>
   <div class="app-page">
-    <h2>{{ ruleLabel }}页签规则</h2>
+    <h2>{{ curRule.label }}页签规则</h2>
 
     <p>你在 <strong class="text-strong">{{ pageTime }}</strong> 秒前打开本页面</p>
 
-    <h3>{{ ruleLabel }}页签规则</h3>
-
-    <p
-      v-if="ruleType === 'global'"
-      class="rule-desc"
-    >
-      页签ID: <strong>route => route.fullPath.replace(route.hash, '')`</strong>
-    </p>
-
-    <p
-      v-else-if="ruleType === 'route'"
-      class="rule-desc"
-    >
-      页签ID: <strong>route => `route-rule/${route.params.catalog}`</strong>
-    </p>
-
-    <p
-      v-else
-      class="rule-desc"
-    >
-      页签ID: <strong>route.path</strong>
-    </p>
+    <table class="demo-table">
+      <tr>
+        <th>规则类型</th>
+        <td>{{ curRule.type }}</td>
+      </tr>
+      <tr>
+        <th>实现方法</th>
+        <td class="rule-fn">
+          {{ curRule.fn }}
+        </td>
+      </tr>
+      <tr>
+        <th>规则说明</th>
+        <td>{{ curRule.desc }}</td>
+      </tr>
+    </table>
 
     <h4>点击下面的链接,并观察页签的变化</h4>
 
@@ -40,7 +34,7 @@
           class="demo-btn"
           :to="`../${cat}/${t}`"
         >
-          {{ cat }}/{{ type }}
+          {{ cat }}/{{ t }}
         </router-link>
         <router-link
           class="demo-btn"
@@ -83,33 +77,47 @@ export default {
       ruleType = 'global'
     }
 
-    let ruleLabel = {
-      default: '默认',
-      route: '路由',
-      global: '全局'
-    }[ruleType]
+    let rules = {
+      default: {
+        label: '默认',
+        type: '内置规则:"path"',
+        fn: 'route => route.path',
+        desc: '相同route.params的路由共用页签'
+      },
+      global: {
+        label: '全局',
+        type: '内置规则:"fullPath"',
+        fn: 'route => route.fullPath.replace(route.hash, \'\')',
+        desc: '相同route.params和route.query的路由共用页签'
+      },
+      route: {
+        label: '路由',
+        type: '自定义规则',
+        fn: 'route => \'route-rule/\' + route.params.catalog',
+        desc: '相同catalog参数的路由共用页签'
+      }
+    }
+
+    let curRule = rules[ruleType]
 
     return {
-      ruleType,
-      ruleLabel,
+      curRule,
       catalog,
       type,
       catalogs: ['a', 'b', 'c'],
       types: [ 1, 2 ],
       link: { catalog, type },
-      routeTab: `${ruleLabel}规则${catalog}/${type}`
+      routeTab: `${curRule.label}规则${catalog}/${type}`
     }
   }
 }
 </script>
 
 <style lang="scss" scoped>
-.rule-desc {
-  strong {
-    font-size: 1rem;
-    font-weight: 600;
-    color: $color-primary;
-  }
+.rule-fn {
+  font-size: 1rem;
+  font-style: italic;
+  color: $color;
 }
 
 .btn-list {