浏览代码

docs: 文档和Demo优化

zhaihaoyi 6 年之前
父节点
当前提交
5322c17ffb
共有 9 个文件被更改,包括 149 次插入133 次删除
  1. 21 5
      README.md
  2. 1 0
      docs/.vuepress/config.js
  3. 4 1
      docs/.vuepress/styles/index.styl
  4. 7 7
      docs/README.md
  5. 46 63
      docs/guide.md
  6. 10 12
      src/components/AppAside.vue
  7. 42 41
      src/components/MenuGroup.vue
  8. 14 0
      src/components/MenuItem.vue
  9. 4 4
      src/router.js

+ 21 - 5
README.md

@@ -24,22 +24,38 @@ Vue Router Tab 是基于 `Vue Router` 的路由页签组件。
 
 目前主流的 `Vue.js` 多页签方案([参考文档](https://panjiachen.github.io/vue-element-admin-site/zh/guide/essentials/tags-view.html#%E5%BF%AB%E6%8D%B7%E5%AF%BC%E8%88%AA-%E6%A0%87%E7%AD%BE%E6%A0%8F%E5%AF%BC%E8%88%AA)),是基于 `<keep-alive>` 和 `<router-view>` 组件实现的,由于通过组件的 `name` 来控制缓存,该方案存在以下缺陷:
 
-1. 配置麻烦:需要同时配置 route 和 页面组件的 `name` 并保持一致,还要确保 `name` 不重复
+1. 配置繁杂:需要同时配置 route 和 页面组件的 `name` 并保持一致,还要确保 `name` 不重复
 
-2. 同一个页面组件不能在不同的路由页签独立缓存,不利于组件的复用
+2. 同一个页面组件难以在不同的路由页签中独立缓存,不利于组件的复用
 
 3. 页面缓存难以清理,需要通过各种钩子来更新页面数据
 
-4. 无法针对路由定制独立的页签规则
+4. 无法定制页签打开的规则
+
+
+另外还有一种方案,是弃用 `Vue Router`,自行实现路由和缓存控制。该方案需要使用其提供的 API 来控制页签打开和切换,对于现有的 `Vue Router` 项目引入改动量比较大。
 
 
 ## Vue Router Tab 方案
 
-针对主流方案的各种问题,`Vue Router Tab` 定制开发了 `<router-alive>` 缓存组件来控制路由页面缓存。
+针对现存方案的各种问题,`Vue Router Tab` 定制开发了 `<router-alive>` 缓存组件来控制路由页面缓存。除了解决了其他方案的不足,`Vue Router Tab` 还拥有以下优势:
+
+1. `Vue Router Tab` 是完全响应 `Vue Router` 路由的。使用熟悉的 `<router-link>` 或者 `router.push` 等 api 即可方便的打开和切换页签,您可以使用 `Vue Router` 的完整功能。
+
+2. `Vue Router Tab` 只依赖 `Vue` 和 `Vue Router` 。不会引入额外的依赖。
+
+3. 配置简单,引入组件后通过路由的 `meta` 配置页签信息即可
+
+4. 可以方便的定制页签的打开规则,精准控制路由页签
+
+5. 丰富的选项提供你可能需要的额外功能和自定义配置
+
+6. 提供完善的文档说明、代码示例和Demo演示
+
 
 ## 功能
 
-- [x] 响应路由变化来新增或切换页签
+- [x] 响应路由变化来打开或切换页签
 - [x] 页签关闭和刷新,右键菜单操作
 - [x] 全局和针对特定路由的[页签规则](docs/guide.md#页签规则)配置
 - [x] [初始页签数据](docs/guide.md#初始展示页签),进入页面时默认显示的页签

+ 1 - 0
docs/.vuepress/config.js

@@ -20,6 +20,7 @@ module.exports = {
       { text: '教程', link: '/guide.html' },
       { text: 'API', link: '/api.html' },
       { text: 'Demo', link: demoUrl },
+      { text: '反馈', link: 'mailto: bihaiyouhong12@126.com?subject=' + encodeURIComponent('vue-router-tab 问题和建议') },
       { text: '主页', link: 'https://bhuh.net' }
     ],
 

+ 4 - 1
docs/.vuepress/styles/index.styl

@@ -42,5 +42,8 @@ $color = #3eaf7c;
 
 // Logo 图片
 .home .hero img
-  width 120px
+  width 180px
+
+.nav-links .nav-link.external
+  margin-right -.5em
   

+ 7 - 7
docs/README.md

@@ -5,12 +5,12 @@ heroText: Vue Router Tab
 tagline: 基于 Vue Router 的路由页签组件。
 actionText: 快速上手 →
 actionLink: ./guide.html
-# features:
-# - title: 简洁至上
-#   details: 以 Markdown 为中心的项目结构,以最少的配置帮助你专注于写作
-# - title: Vue驱动
-#   details: 享受 Vue + webpack 的开发体验,在 Markdown 中使用 Vue 组件,同时可以使用 Vue 来开发自定义主题
-# - title: 高性能
-#   details: VuePress 为每个页面预渲染生成静态的 HTML,同时在页面被加载的时候,将作为 SPA 运行
+features:
+- title: 简洁至上
+  details: 配置简单,引入组件后通过路由的 "meta" 元信息配置页签信息即可运行
+- title: 规则定制
+  details: 方便定制页签规则。除了默认的规则,您还可以全局和精准控制每个路由的页签打开方式
+- title: Vue Router 驱动
+  details: 页签响应 "Vue Router" 路由,您可以使用 "Vue Router" 提供的强大功能
 footer: MIT Licensed | Copyright © 2019-present bhuh12
 ---

+ 46 - 63
docs/guide.md

@@ -22,7 +22,7 @@ yarn add vue-router-tab
 **示例:**
 
 ``` javascript {8,9,15}
-// @/main.js
+// @/main.js 入口
 
 // router-tab 组件依赖 vue 和 vue-router
 import Vue from 'vue'
@@ -56,7 +56,7 @@ new Vue({
 **示例:**
 
 ``` html {6}
-<!-- @/components/layout/Admin.vue -->
+<!-- @/components/layout/Frame.vue 布局框架 -->
 <template>
   <div class="app-header">头部</div>
   <div class="app-body">
@@ -66,23 +66,23 @@ new Vue({
 </template>
 ```
 
-### 路由配置
+### 页签信息配置
 
-通过路由的 `meta` 信息,来设置页签的**标题**、**图标**、**提示**和页签**缓存规则**
+通过路由的 `meta` 信息,来设置页签的**标题**、**图标**、**提示**和**路由页签规则**
 
-配置参考: [Route.meta 路由元](api.md#route-meta-路由元)
+配置参考: [Route.meta 路由元信息](api.md#route-meta-路由元信息)
 
 **示例:**
 
-``` javascript {17,21,22,23,24,28,29,30,31,32}
-// @/router.js
+``` javascript {5,6,17,18,21,22,23,24,25,26}
+// @/router.js 路由
 import Vue from 'vue'
 import Router from 'vue-router'
 
-// 引入布局和页面
-import Admin from './components/layout/Admin.vue'
+// 引入布局框架组件
+import Frame from './components/layout/Frame.vue'
 
-// 异步页面组件
+// 异步加载页面组件
 const importPage = view => () => import(/* webpackChunkName: "p-[request]" */ `./views/${view}.vue`)
 
 Vue.use(Router)
@@ -91,21 +91,15 @@ export default new Router({
   routes: [{
     path: '/',
     redirect: '/page1',
-    component: Admin,
-    children: [{
-      path: '/page1',
-      component: importPage('Page1'),
+    component: Frame, // 父路由组件内必须包含 <router-tab>
+    children: [{ // 子路由里配置需要通过页签打开的页面路由
+      path: '/page/:id',
+      component: importPage('Page'),
       meta: {
-        title: '页面1',
-        icon: 'icon-doc'
-      }
-    }, {
-      path: '/page2/:id',
-      component: importPage('Page2'),
-      meta: {
-        title: '页面2',
-        icon: 'icon-user',
-        tips: '这是页面2'
+        title: '页面', // 页签标题
+        icon: 'icon-user', // 页签图标,可选
+        tips: '这是一个页面', // 页签提示,可选,如未设置则跟title一致
+        aliveKey: 'fullPath', // 路由打开页签规则,可选
       }
     }, {
       path: '/404',
@@ -160,7 +154,9 @@ export default new Router({
 您可以通过 `RouterTab` 的实例方法 [`routerTab.close(location, fullMatch?)`](api.md#routertab-close) 来关闭页签
 
 ::: tip
-在 Vue 实例内部,您可以通过 `$routerTab` 访问路由页签实例。因此您可以调用 `this.$routerTab.close`。
+1. 在 Vue 实例内部,您可以通过 `$routerTab` 访问路由页签实例。因此您可以调用 `this.$routerTab.close`。
+
+2. 当 `RouterTab` 组件只有一个页签,或者初始页签的 `closable` 配置为 `false`,页签关闭操作将不生效。
 :::
 
 <doc-links api="#routertab-close" demo="/default/"></doc-links>
@@ -286,7 +282,9 @@ this.$routerTab.refreshAll(true)
 <router-tab :alive-id="route => route.fullPath.replace(route.hash, '')"/>
 ```
 
-例子中,配置 `alive-id` 为 `fullPath` 去除 `hash` 部分。这样,“page/1” 和 “page/1?query=2”、“page/2”、“page/2?query=2” 这四个地址都是打开不同的页签。而 “page/1” 和 “page/1#hash1” 是同一个页签,因为它们忽略 `hash` 后的路径一致。
+例子中,配置 `alive-id` 为 `fullPath` 去除 `hash` 部分。
+
+根据该规则,`page/1` 和 `page/1?query=2`、`page/2`、`page/2?query=2` 这四个地址都是打开**不同**的页签。而 `page/1` 和 `page/1#hash1` 是同一个页签,因为它们忽略 `hash` 后的路径一致。
 
 
 ### 路由页签规则
@@ -297,38 +295,23 @@ this.$routerTab.refreshAll(true)
 
 **示例:**
 
-``` javascript {19,21,23,24,25}
-// @/router.js
-import Vue from 'vue'
-import Router from 'vue-router'
-
-// 引入布局和页面
-import Admin from './components/layout/Admin.vue'
-
-// 异步页面组件
-const importPage = view => () => import(/* webpackChunkName: "p-[request]" */ `./views/${view}.vue`)
-
-Vue.use(Router)
-
-export default new Router({
-  routes: [{
-    path: '/',
-    redirect: '/route-rule/a/1',
-    component: Admin,
-    children: [{
-      path: 'route-rule/:catalog/:type',
-      component: importPage('CustomRule'),
-      meta: {
-        title: '定制规则',
-        aliveId (route) {
-          return `route-rule/${route.params.catalog}`
-        }
-      }
-    }]
-  }]
-})
+``` javascript {8,9,10}
+const route = {
+  path: '/my-page/:catalog/:type',
+  component: {
+    template: '<div>定制规则:{{$route.params.catalog}}/{{$route.params.type}}</div>'
+  },
+  meta: {
+    title: '定制规则',
+    aliveId (route) {
+      return `/my-page/${route.params.catalog}`
+    }
+  }
+}
 ```
 
+根据示例中的页签规则,`/my-page/a/1` 和 `/my-page/a/2` 打开的是**同一个**页签。而 `/my-page/b/1` 和 `/my-page/b/2` 则打开另外一个页签
+
 
 ## 进阶
 
@@ -445,7 +428,7 @@ export default new Router({
   <router-tab :tabs="tabs"/>
   ```
 
-  ``` javascript {7}
+  ``` javascript {7,10,13,16,17,18,19,20,21,22}
   export default {
     data () {
       return {
@@ -454,7 +437,7 @@ export default new Router({
           // 推荐 fullPath 方式配置默认页签项。RouterTab 会自动获取路由里的页签配置
           '/page/1',
 
-          // 设置初始 title,用于需要动态展示页签信息的路由页面
+          // 设置初始 title,用于需要动态更新页签信息的路由页面
           { to: '/page/2', title: '页面2', icon: 'icon-page' },
 
           // 设置 closable 为 false,可以禁止页签被关闭
@@ -485,7 +468,7 @@ export default new Router({
 
 **示例:**
 
-``` javascript {8,11}
+``` javascript {8,11,12,13,14,15}
 export default {
   name: 'page',
   mounted () {
@@ -514,7 +497,7 @@ export default {
 
 `RouterTab` 默认语言是 `zh-CN`,另外内置了 `en`。
 
-<doc-links api="#i18n" demo="/language/"></doc-links>
+<doc-links api="#i18n" demo="/lang-en/"></doc-links>
 
 **指定组件显示为英文**
 
@@ -522,17 +505,17 @@ export default {
 <router-tab i18n="en"/>
 ```
 
-**自定义的语言**
+**自定义的语言** ([参考配置](https://github.com/bhuh12/vue-router-tab/blob/dev/src/lib/RouterTab/lang/en.js))
 
 ``` html
-<router-tab :i18n="lang"/>
+<router-tab :i18n="customLanguage"/>
 ```
 
 ``` javascript
 export default {
   data () {
     return {
-      lang: {
+      customLanguage: {
         tab: {
           untitled: 'Untitled Page'
         },

+ 10 - 12
src/components/AppAside.vue

@@ -19,32 +19,30 @@ export default {
   data () {
     return {
       menu: [{
-        title: 'RouterTab 配置',
-        data: [
+        text: 'RouterTab 配置',
+        children: [
           { text: '默认配置', to: '/default/' },
           { text: '过渡效果', to: '/transition/' },
           { text: '初始展示页签', to: '/initial-tabs/' },
           {
             text: '语言配置',
-            to: '/language/',
-            children: {
-              data: [
-                { text: '自定义语言', to: '/language/custom' }
-              ]
-            }
+            children: [
+              { text: '指定语言', to: '/lang-en/' },
+              { text: '自定义语言', to: '/lang-custom' }
+            ]
           },
           { text: '自定义页签模板', to: '/slot/' }
         ]
       }, {
-        title: '页签规则',
-        data: [
+        text: '页签规则',
+        children: [
           { text: '默认页签规则', to: '/default/rule/a/1' },
           { text: '全局页签规则', to: '/global-rule/rule/a/1' },
           { text: '路由页签规则', to: '/default/route-rule/a/1' }
         ]
       }, {
-        title: '页面配置',
-        data: [
+        text: '页面配置',
+        children: [
           { text: '动态更新页签配置', to: '/default/tab-dynamic' },
           { text: '页面离开确认', to: '/initial-tabs/page-leave' }
         ]

+ 42 - 41
src/components/MenuGroup.vue

@@ -1,64 +1,65 @@
 <template>
-  <div class="menu-group">
-    <h3 class="menu-title" v-if="data.title">{{data.title}}</h3>
-    <ul class="menu-list">
-      <li class="menu-item" v-for="item in data.data" :key="item.to">
-        <router-link :to="item.to">{{item.text}}</router-link>
-        <menu-group v-if="item.children" :data="item.children"/>
-      </li>
-    </ul>
+  <div class="menu-group" v-if="data.children && data.children.length">
+    <menu-item :data="data"/>
+    <div class="menu-list">
+      <menu-group v-for="(item, index) in data.children" :key="index" :data="item"/>
+    </div>
   </div>
+
+  <menu-item v-else :data="data"/>
 </template>
 
 <script>
+import MenuItem from './MenuItem.vue'
+
 export default {
   name: 'MenuGroup',
   props: {
     data: Object
-  }
+  },
+  components: { MenuItem }
 }
 </script>
 
 <style lang="scss" scoped>
-.menu-group {
-  .menu-title {
-    padding: 0 1.25rem;
-    margin-top: 0;
-    margin-bottom: .5rem;
-    font-size: 1.1em;
-    font-weight: 600;
-  }
+$fs: .875rem;
+.menu-item {
+  display: block;
+  padding: .35rem 1rem .35rem 1.25rem;
+  font-size: $fs;
+  color: #2c3e50;
+  text-decoration: none;
+  cursor: pointer;
 
-  .menu-list {
-    margin: 0;
-    padding: 0;
-    padding-left: 1rem;
+  &.router-link-active,
+  &:hover {
+    color: $color;
   }
 
-  .menu-item {
-    list-style: none;
-    font-size: .875rem;
+  &.router-link-active {
+    font-weight: 700;
+  }
+}
 
-    > a {
-      display: block;
-      padding: .35rem 1rem .35rem 1.25rem;
-      color: #2c3e50;
-      text-decoration: none;
-      cursor: pointer;
+.menu-title {
+  padding: 0 1.25rem;
+  margin: .5rem 0;
+  font-size: 1.1em;
+  font-weight: 600;
+}
 
-      &.router-link-active,
-      &:hover {
-        color: $color;
-      }
+.menu-list {
+  margin: 0;
+  padding: 0;
+  padding-left: 1rem;
 
-      &.router-link-active {
-        font-weight: 700;
-      }
-    }
+  .menu-list .router-link-active {
+    font-weight: 400;
+  }
 
-    .menu-group .router-link-active {
-        font-weight: 400;
-    }
+  .menu-group .menu-title {
+    margin: .3rem 0;
+    font-size: $fs;
   }
 }
 </style>

+ 14 - 0
src/components/MenuItem.vue

@@ -0,0 +1,14 @@
+<template>
+  <h3 class="menu-title" v-if="data.text && !data.to">{{data.text}}</h3>
+
+  <router-link class="menu-item" v-else-if="data.to" :to="data.to">{{data.text}}</router-link>
+</template>
+
+<script>
+export default {
+  name: 'MenuItem',
+  props: {
+    data: Object
+  }
+}
+</script>

+ 4 - 4
src/router.js

@@ -68,14 +68,14 @@ export default new Router({
     redirect: '/initial-tabs/page/1',
     children: pageRoutes
   }, {
-    path: '/language/',
+    path: '/lang-en/',
     component: importLayout('Language'),
-    redirect: '/language/page/1',
+    redirect: '/lang-en/page/1',
     children: pageRoutes
   }, {
-    path: '/language/custom/',
+    path: '/lang-custom/',
     component: importLayout('LanguageCustom'),
-    redirect: '/language/custom/page/1',
+    redirect: '/lang-custom/page/1',
     children: pageRoutes
   }, {
     path: '/slot/',